如果不了解Oauth2 是什么、工作流程的可以看我上一篇文章:
SpringCloud-OAuth2(一):基础篇

这篇讲的内容是:Oauth2在SpringBoot/SpringCloud中的实战。

SpringBoot版本:2.2.5.Release
SpringCloud版本:Hoxton.SR9
JDK版本:1.8

  1. <dependencies>
  2. <!-- https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2 -->
  3. <dependency>
  4. <artifactId>spring-cloud-starter-oauth2</artifactId>
  5. <groupId>org.springframework.cloud</groupId>
  6. </dependency>
  7. <!--使用redis存放token-->
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter-data-redis</artifactId>
  11. </dependency>
  12. <!--密码加密解密依赖包-->
  13. <dependency>
  14. <groupId>org.jasypt</groupId>
  15. <artifactId>jasypt</artifactId>
  16. <version>1.9.2</version>
  17. </dependency>
  18. </dependencies>
  1. @Configuration
  2. @EnableAuthorizationServer
  3. public class WebAuthorizationConfig extends AuthorizationServerConfigurerAdapter {
  4. private final AuthenticationManager authenticationManager;
  5. private final UserDetailsService userDetailsService;
  6. private final PasswordEncoder passwordEncoder;
  7. private final TokenStore tokenStore;
  8. private final AuthorizationCodeServices authorizationCodeServices;
  9. private final AuthTokenExceptionHandler authTokenExceptionHandler;
  10. public WebAuthorizationConfig(AuthenticationManager authenticationManager,
  11. UserDetailsService userDetailsService,
  12. PasswordEncoder passwordEncoder,
  13. TokenStore tokenStore,
  14. AuthorizationCodeServices authorizationCodeServices,
  15. AuthTokenExceptionHandler authTokenExceptionHandler) {
  16. this.authenticationManager = authenticationManager;
  17. this.userDetailsService = userDetailsService;
  18. this.passwordEncoder = passwordEncoder;
  19. this.tokenStore = tokenStore;
  20. this.authorizationCodeServices = authorizationCodeServices;
  21. this.authTokenExceptionHandler = authTokenExceptionHandler;
  22. }
  23. @Override
  24. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  25. String secret = PasswordHelper.encryptPassword(Oauth2ClientUserEnums.ADMIN.getClientSecret());
  26. clients.inMemory()
  27. .withClient(Oauth2ClientUserEnums.ADMIN.getClientId())
  28. .secret(secret)
  29. .scopes("all", "test")
  30. .resourceIds("admin")
  31. // autoApprove 可跳过授权页直接返回code
  32. .autoApprove("all")
  33. .redirectUris("http://www.baidu.com")
  34. //客户端认证所支持的授权类型 1:客户端凭证 2:账号密码 3:授权码 4:token刷新 5:简易模式
  35. .authorizedGrantTypes(CLIENT_CREDENTIALS, PASSWORD, REFRESH_TOKEN, AUTHORIZATION_CODE, IMPLICIT)
  36. //用户角色
  37. .authorities("admin")
  38. //允许自动授权
  39. .autoApprove(false)
  40. //token 过期时间
  41. .accessTokenValiditySeconds((int) TimeUnit.HOURS.toSeconds(12))
  42. //refresh_token 过期时间
  43. .refreshTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30))
  44. ;
  45. }
  46. @Override
  47. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  48. security
  49. .passwordEncoder(passwordEncoder) //设置密码编辑器
  50. .allowFormAuthenticationForClients()
  51. .tokenKeyAccess("permitAll()") //开启 /oauth/token_key 的访问权限控制
  52. .checkTokenAccess("permitAll()") //开启 /oauth/check_token 验证端口认证权限访问
  53. ;
  54. }
  55. @Override
  56. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  57. // 配置授权服务器端点的属性
  58. endpoints.authenticationManager(authenticationManager) //认证管理器
  59. .tokenStore(tokenStore)
  60. .authorizationCodeServices(authorizationCodeServices)
  61. .userDetailsService(userDetailsService)
  62. .exceptionTranslator(authTokenExceptionHandler);
  63. }
  64. }

注解:@EnableAuthorizationServer表明当前服务是认证服务。


介绍一下几个基础组件


①:authenticationManager
认证管理器,对客户端凭证、用户进行认证的地方。


②:tokenStore
存放token的地方,默认是存放在Inmemory(内存)中的。


③:authorizationCodeServices
code生成服务,使用默认的即可。


④:userDetailsService
用户详情服务,可重写实现,用户信息从数据库中加载。


⑤:authTokenExceptionHandler
自定义的 token 鉴别失败异常处理器。


⑥:authClientExceptionHandler
自定义的 客户端凭证 鉴别失败异常处理器。

  1. @Configuration
  2. @EnableResourceServer
  3. public class WebResourceConfig extends ResourceServerConfigurerAdapter {
  4. private final AuthClientExceptionHandler authClientExceptionHandler;
  5. public WebResourceConfig(AuthClientExceptionHandler authClientExceptionHandler) {
  6. this.authClientExceptionHandler = authClientExceptionHandler;
  7. }
  8. @Override
  9. public void configure(ResourceServerSecurityConfigurer resources) {
  10. resources.resourceId("admin").stateless(true).authenticationEntryPoint(authClientExceptionHandler);
  11. }
  12. @Override
  13. public void configure(HttpSecurity http) throws Exception {
  14. // 资源链路
  15. http
  16. .sessionManagement()
  17. .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
  18. .and().formLogin().permitAll()
  19. // 登录放通
  20. .and()
  21. .authorizeRequests()
  22. .antMatchers("/oauth/**", "/favicon.ico")
  23. //.authenticated()
  24. .permitAll()
  25. // 其他请求都需认证
  26. .and()
  27. .authorizeRequests()
  28. .anyRequest()
  29. .authenticated()
  30. // 跨域
  31. .and()
  32. .cors()
  33. // 关闭跨站请求防护
  34. .and()
  35. .csrf()
  36. .disable();
  37. }
  38. }

注解:@EnableResourceServer表明当前服务是认证服务。

笔记:
为什么要放开 /favicon.ico 的访问权限?因为在进行授权码模式的时候,一直无法跳转到我定义的redirect_uri 地址中去。
使用 logging.level.org.springframework.security=debug 发现会访问 /favicon.ico ,然后报错,再然后就是调到登录页去了。
因此 /favicon.ico 放开之后,认证正常,成功调到redirect_uri 地址并返回了code。(这是OAuth2的小坑吗?)

  1. @Configuration
  2. @EnableWebSecurity
  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  4. private final PasswordEncoder passwordEncoder;
  5. public WebSecurityConfig(PasswordEncoder passwordEncoder) {
  6. this.passwordEncoder = passwordEncoder;
  7. }
  8. @Override
  9. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  10. auth
  11. .userDetailsService(userDetailsService())
  12. .passwordEncoder(passwordEncoder); //为认证管理器配置passwordEncoder,无论客户端凭证密码还是用户密码都通过passwordEncoder进行密码匹配
  13. }
  14. @Bean
  15. @Override
  16. protected UserDetailsService userDetailsService() {
  17. return new VipUserDetailService();
  18. }
  19. @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
  20. @Override
  21. public AuthenticationManager authenticationManagerBean() throws Exception {
  22. return super.authenticationManagerBean();
  23. }
  24. }

详细配置可以翻阅我的GitHub:GitHub地址

注意!!!一定要配置redirect_uri,并且一定要允许表单登录!!!
以下是步骤:


①:浏览器输入以下链接地址,会重定向到登录页
http://localhost:8123/oauth/authorize?client_id=admin&client_secret=admin&response_type=code&redirect_uri=http://www.baidu.com&scope=test

drawing


②:输入配置的用户名密码,回调到授权页

drawing

如果我们配置的scope是autoApprove的,即可跳过这步,直接到第③步,拿到code。


③:选择 Approve,点击Authorize 即可调到redirect_uri地址
drawing


④:拿code 换 token

我的请求地址:127.0.0.1:8123/oauth/token?grant_type=authorization_code&code=h35Fh1&redirect_uri=http://www.baidu.com
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。

drawing

我的请求地址:127.0.0.1:8123/oauth/token?grant_type=password&username=found&password=123456
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。

drawing

我的请求地址:127.0.0.1:8123/oauth/token?grant_type=client_credentials
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。

drawing

浏览器输入以下地址即可拿到token:
http://localhost:8123/oauth/authorize?client_id=admin&client_secret=admin&response_type=token&redirect_uri=http://www.baidu.com

drawing

我的请求地址:127.0.0.1:8123/oauth/token?grant_type=refresh_token&refresh_token=dde5f388-4ad7-4781-a1b7-aaafb3c34b10
refresh_token是服务器颁发给客户端的,作用就是在一定时间内,让用户不用重新登录。
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。

drawing

个人认为做第三方登录是当前比较流行的做法。

①:比如我们现在登录processOn,就可以选择第三方登录。

drawing


②:点击QQ登录后会调到这个页面↓↓↓↓↓↓↓↓↓↓↓↓

drawing


③:这个client_id 应该就是processOn 官方申请的第三方客户端凭证了。
选择账号密码登录,输入账号密码之后就可以拿到token,(我手速快截了个图)

drawing


④:可以看到返回了access_token、过期时间。
随后processOn既发起请求进行登录操作,登录成功进入用户首页,失败则重定向到登录页。
drawing
drawing

drawing

可以看到不需要用户进行Authorize操作即可拿到token了,说明QQ第三方认证中心设置的scope=all是autoApprove的。

总结 :
学习总要从身边找例子,这样才能更好的理解。

版权声明:本文为zgq7原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zgq7/p/14890577.html