SpringCloud-OAuth2(二):实战篇
如果不了解Oauth2 是什么、工作流程的可以看我上一篇文章:
SpringCloud-OAuth2(一):基础篇
这篇讲的内容是:Oauth2在SpringBoot/SpringCloud中的实战。
SpringBoot版本:2.2.5.Release
SpringCloud版本:Hoxton.SR9
JDK版本:1.8
1:POM配置
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2 --> <dependency> <artifactId>spring-cloud-starter-oauth2</artifactId> <groupId>org.springframework.cloud</groupId> </dependency> <!--使用redis存放token--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--密码加密解密依赖包--> <dependency> <groupId>org.jasypt</groupId> <artifactId>jasypt</artifactId> <version>1.9.2</version> </dependency> </dependencies>
2:关键配置
2.1:认证服务配置-WebAuthorizationConfig
@Configuration @EnableAuthorizationServer public class WebAuthorizationConfig extends AuthorizationServerConfigurerAdapter { private final AuthenticationManager authenticationManager; private final UserDetailsService userDetailsService; private final PasswordEncoder passwordEncoder; private final TokenStore tokenStore; private final AuthorizationCodeServices authorizationCodeServices; private final AuthTokenExceptionHandler authTokenExceptionHandler; public WebAuthorizationConfig(AuthenticationManager authenticationManager, UserDetailsService userDetailsService, PasswordEncoder passwordEncoder, TokenStore tokenStore, AuthorizationCodeServices authorizationCodeServices, AuthTokenExceptionHandler authTokenExceptionHandler) { this.authenticationManager = authenticationManager; this.userDetailsService = userDetailsService; this.passwordEncoder = passwordEncoder; this.tokenStore = tokenStore; this.authorizationCodeServices = authorizationCodeServices; this.authTokenExceptionHandler = authTokenExceptionHandler; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { String secret = PasswordHelper.encryptPassword(Oauth2ClientUserEnums.ADMIN.getClientSecret()); clients.inMemory() .withClient(Oauth2ClientUserEnums.ADMIN.getClientId()) .secret(secret) .scopes("all", "test") .resourceIds("admin") // autoApprove 可跳过授权页直接返回code .autoApprove("all") .redirectUris("http://www.baidu.com") //客户端认证所支持的授权类型 1:客户端凭证 2:账号密码 3:授权码 4:token刷新 5:简易模式 .authorizedGrantTypes(CLIENT_CREDENTIALS, PASSWORD, REFRESH_TOKEN, AUTHORIZATION_CODE, IMPLICIT) //用户角色 ad8 .authorities("admin") //允许自动授权 .autoApprove(false) //token 过期时间 .accessTokenValiditySeconds((int) TimeUnit.HOURS.toSeconds(12)) //refresh_token 过期时间 .refreshTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)) ; } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security .passwordEncoder(passwordEncoder) //设置密码编辑器 .allowFormAuthenticationForClients() .tokenKeyAccess("permitAll()") //开启 /oauth/token_key 的访问权限控制 .checkTokenAccess("permitAll()") //开启 /oauth/check_token 验证端口认证权限访问 ; } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 配置授权服务器端点的属性 endpoints.authenticationManager(authenticationManager) //认证管理器 .tokenStore(tokenStore) .authorizationCodeServices(authorizationCodeServices) .userDetailsService(userDetailsService) .exceptionTranslator(authTokenExceptionHandler); } }
注解:@EnableAuthorizationServer表明当前服务是认证服务。
介绍一下几个基础组件
①:authenticationManager
认证管理器,对客户端凭证、用户进行认证的地方。
②:tokenStore
存放token的地方,默认是存放在Inmemory(内存)中的。
③:authorizationCodeServices
code生成服务,使用默认的即可。
④:userDetailsService
用户详情服务,可重写实现,用户信息从数据库中加载。
⑤:authTokenExceptionHandler
自定义的 token 鉴别失败异常处理器。
⑥:authClientExceptionHandler
自定义的 客户端凭证 鉴别失败异常处理器。
2.2:资源服务配置-WebResourceConfig
@Configuration @EnableResourceServer public class WebResourceConfig extends ResourceServerConfigurerAdapter { private final AuthClientExceptionHandler authClientExceptionHandler; public WebResourceConfig(AuthClientExceptionHandler authClientExceptionHandler) { this.authClientExceptionHandler = authClientExceptionHandler; } @Override public void configure(ResourceServerSecurityConfigurer resources) { resources.resourceId("admin").stateless(true).authenticationEntr ad0 yPoint(authClientExceptionHandler); } @Override public void configure(HttpSecurity http) throws Exception { // 资源链路 http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and().formLogin().permitAll() // 登录放通 .and() .authorizeRequests() .antMatchers("/oauth/**", "/favicon.ico") //.authenticated() .permitAll() // 其他请求都需认证 .and() .authorizeRequests() .anyRequest() .authenticated() // 跨域 .and() .cors() // 关闭跨站请求防护 .and() .csrf() .disable(); } }
注解:@EnableResourceServer表明当前服务是认证服务。
笔记:
为什么要放开 /favicon.ico 的访问权限?因为在进行授权码模式的时候,一直无法跳转到我定义的redirect_uri 地址中去。
使用 logging.level.org.springframework.security=debug 发现会访问 /favicon.ico ,然后报错,再然后就是调到登录页去了。
因此 /favicon.ico 放开之后,认证正常,成功调到redirect_uri 地址并返回了code。(这是OAuth2的小坑吗?)
2.3:安全配置-WebSecurityConfig
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final PasswordEncoder passwordEncoder; public WebSecurityConfig(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userDetailsService()) .passwordEncoder(passwordEncoder); //为认证管理器配置passwordEncoder,无论客户端凭证密码还是用户密码都通过passwordEncoder进行密码匹配 } @Bean @Override protected UserDetailsService userDetailsService() { return new VipUserDetailService(); } @Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
详细配置可以翻阅我的GitHub:GitHub地址
3:认证授权演示
3.1:授权码模式
注意!!!一定要配置redirect_uri,并且一定要允许表单登录!!!
以下是步骤:
①:浏览器输入以下链接地址,会重定向到登录页
http://localhost:8123/oauth/authorize?client_id=admin&client_secret=admin&response_type=code&redirect_uri=http://www.baidu.com&scope=test
②:输入配置的用户名密码,回调到授权页
如果我们配置的scope是autoApprove的,即可跳过这步,直接到第③步,拿到code。
③:选择 Approve,点击Authorize 即可调到redirect_uri地址
④:拿code 换 token
我的请求地址:127.0.0.1:8123/oauth/token?grant_type=authorization_code&code=h35Fh1&redirect_uri=http://www.baidu.com
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。
3.2:用户密码模式
我的请求地址:127.0.0.1:8123/oauth/token?grant_type=password&username=found&password=123456
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。
3.3:客户端凭证模式
我的请求地址:127.0.0.1:8123/oauth/token?grant_type=client_credentials
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。
3.4:隐式授权模式
浏览器输入以下地址即可拿到token:
ht
1bbc
tp://localhost:8123/oauth/authorize?client_id=admin&client_secret=admin&response_type=token&redirect_uri=http://www.baidu.com
3.5:token 刷新
我的请求地址:127.0.0.1:8123/oauth/token?grant_type=refresh_token&refresh_token=dde5f388-4ad7-4781-a1b7-aaafb3c34b10
refresh_token是服务器颁发给客户端的,作用就是在一定时间内,让用户不用重新登录。
需要配置Authorization,请求时会将客户端凭证以base64格式放在请求头中。
4:聊聊第三方登录
个人认为做第三方登录是当前比较流行的做法。
4.1:流程
①:比如我们现在登录ProcessOn,就可以选择第三方登录。
②:点击QQ登录后会调到这个页面↓↓↓↓↓↓↓↓↓↓↓↓
③:上面这个client_id 应该就是ProcessOn 官方申请的第三方客户端凭证了。
选择账号密码登录,输入账号密码之后就可以拿到token,(我手速快截了个图)
④:可以看到返回了access_token、过期时间。
随后processOn既发起请求进行登录操作,登录成功进入用户首页,失败则重定向到登录页。
4.2:uml图
认真辨别了一下,QQ第三方登录采用不是授权码模式,而是Implicat Grant Type。(差点看走眼)
总结 :
学习总要从身边找例子,这样才能更好的理解。
- SpringCloud微服务实战之分布式服务跟踪Sleuth
- SpringCloud Eureka实战
- SpringCloud Alibaba微服务实战 - 基础环境准备
- Spring Cloud Sleuth进阶实战
- SpringCloudGateWay实战(一)- Zuul及其实现原理
- 最新微服务架构 Spring Cloud 实战百讲课程
- Spring Cloud微服务实战---1.1.配置开发环境
- Spring cloud实战-Fegin简易使用
- Spring Cloud精华视频 Spring Cloud微服务实战视频教程
- Spring Cloud 笔记实战之 Spring Cloud Config
- Spring Cloud 快速入门实战笔记
- springcloud实战之6 服务消费者(Feign)
- Spring Cloud微服务实战教程系列(一)——Spring Cloud微服务简介
- Github点赞接近 70k 的Spring Cloud学习教程+实战项目推荐!牛批!
- spring cloud 零基础实战
- spring cloud微服务架构项目实战(共计10套)
- 传智播客idea版springcloud微服务实战
- Springboot SpringCloud集成OAuth2入门详细教程
- Spring Cloud 微服务开发:入门、进阶与源码剖析 —— 12.3 Sentinel 进阶实战
- SpringCloud微服务实战