当前位置:   article > 正文

六、SpringSecurity OAuth2 + SpringCloud Gateway实现统一鉴权管理_spring security oauth2 + spring cloud gateway

spring security oauth2 + spring cloud gateway

代码

代码仓库:地址

代码分支:lesson6

博客:地址

简介

在先前文章中,我们使用SpringSecurity OAuth2搭建了一套基于OAuth2协议的授权系统,并扩展了手机验证码授权模式。在微服务架构下,网关承担着流量入口的角色,所有的请求都要先经过网关,然后由网关负责转发到具体的服务,因此可以在网关实现统一鉴权,网关对请求中的权限进行鉴定,然后将权限信息转发到具体的资源服务,在资源服务中只需要简单校验请求中的权限信息即可(查看信息是否有效),整体流程如下所示:

统一鉴权

SpringCloud Gateway网关

我们在上一篇的基础上引入网关服务,在这里使用SpringCloud Gateway组件进行搭建,引入依赖:

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-gateway</artifactId>
  4. </dependency>

网关在OAuth2授权协议中承担着资源服务的角色,对请求进行身份鉴定和访问权限控制,身份鉴定需要访问OAuth2授权服务,因此需要引入OAuth2资源服务以及客户端依赖:

  1. <dependency>
  2. <groupId>org.springframework.security</groupId>
  3. <artifactId>spring-security-oauth2-resource-server</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-oauth2-client</artifactId>
  8. </dependency>

通过之前的文章,我们可以知道SpringSecurity 通过组装一系列的Filter来完成身份验证和权限访问控制功能,但是SpringCloud Gateway使用了新技术框架Reactive Stack(响应式编程),在Spring中提供了Spring WebFlux模块支持响应式编程,传统的Spring MVC都是基于阻塞I/O编程,而Spring WebFlux是基于非阻塞I/O,我们不再这里讨论这两个的区别,只需要知道WebFlux特别适合I/O密集型性应用,网关就是典型的I/O密集应用(网络I/O处理频繁)。SpringSecurity对WebFlux提供了支持,在WebFlux中WebFilter组件承担着与Filter相似的功能。

我们在先前的应用中通过HttpSecurity组件来组装SpringSecurity功能,在这里要使用新的组件ServerHttpSecurity来组装SpringSecurity功能,配置如下所示:

  1. ///启用WebFlux下的SpringSecurity配置
  2. @EnableWebFluxSecurity
  3. public class ResourceServerConfig {
  4. 访问权限验证
  5. @Autowired
  6. AuthManagerHandler authManagerHandler;
  7. 无权限访问处理器
  8. @Autowired
  9. AccessDeniedHandler accessDeniedHandler;
  10. /// 登录信息失效处理器
  11. @Autowired
  12. LoginLoseHandler loginLoseHandler;
  13. 访问白名单,对白名单路径可以实现匿名访问
  14. @Autowired
  15. private WhiteUrlProperties whiteUrlProperties;
  16. @Bean
  17. public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  18. http.oauth2ResourceServer()
  19. /// 这里配置对令牌的校验,从OAuth2授权服务中获取令牌对应的授权信息
  20. .opaqueToken()
  21. ///令牌校验地址,用于校验令牌是否有效,已经令牌对应的授权信息
  22. .introspectionUri("http://localhost:8081/oauth/check_token")
  23. 客户端信息
  24. .introspectionClientCredentials("blog", "blog")
  25. .and()
  26. .accessDeniedHandler(accessDeniedHandler)
  27. .authenticationEntryPoint(loginLoseHandler)
  28. .and().authorizeExchange()
  29. .pathMatchers(HttpMethod.OPTIONS).permitAll() //o
  30. .pathMatchers("/**").access(authManagerHandler)
  31. .anyExchange().authenticated()
  32. .and()
  33. .addFilterBefore(securityGlobalFilter(whiteUrlProperties), SecurityWebFiltersOrder.FIRST)
  34. .cors().disable().csrf().disable();
  35. return http.build();
  36. }
  37. /// 该过滤器实现将获取到的授权信息转发到下游服务中,方便后续校验
  38. public WebFilter securityGlobalFilter(WhiteUrlProperties properties) {
  39. return new SecurityGlobalFilter(properties);
  40. }
  41. }

网关路由配置以及其它细节信息可以前往代码仓库进行查看,在此不做过多解释。

资源服务器

资源服务器也需要做一些调整,不需要对请求进行严格的访问控制,只需要校验网关传递的授权信息即可,然后将授权信息放入到SecurityContext中方便后续处理,同时需要注意在资源服务中还是使用Spring MVC框架进行处理(Spring WebFlux可以提高系统吞吐量,但是也会增加编程难度,例如原先的线程变量将不适用,具体需要考量整体编程人员掌握的技术栈来做决定)。

这里的资源服务器不再依赖OAuth授权服务,因此可以移除@EnableResourceServer配置(不直接参与权限控制,只需要校验上游传递的授权信息是否有效即可),同时增加对上游SpringCloud Gateway传递的授权信息进行解析处理,增加自定义SecurityAuthTokenFilter组件:

  1. public class SecurityAuthTokenFilter extends OncePerRequestFilter {
  2. private static final String AUTH_TOKEN_NAME = "token";
  3. @Override
  4. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
  5. FilterChain filterChain) throws ServletException, IOException {
  6. String token = request.getHeader(AUTH_TOKEN_NAME);
  7. if (StringUtils.isEmpty(token)) {
  8. /// 继续处理
  9. filterChain.doFilter(request, response);
  10. return;
  11. }
  12. ///....省略处理细节,具体前往代码仓库进行查看
  13. 创建自定义的Authentication对象,必须申明为已授权,也就是isAuthenticated()方法返回为true
  14. BlogAuthentication authentication = new BlogAuthentication(userId, clientId, authorities);
  15. //....省略处理细节,具体前往代码仓库进行查看
  16. /// 将授权信息放入到SecurityContext中,方便后续使用
  17. SecurityContextHolder.getContext().setAuthentication(authentication);
  18. filterChain.doFilter(request, response);
  19. }
  20. }

运行验证

分别运行Gateway网关服务、OAuth授权服务、Resource资源服务

  • Gateway 8080端口
  • OAuth 8081端口
  • Resource 8082端口

授权登录

使用密码模式进行授权登录,发送请求POST http://localhost:8080/blog-oauth/oauth/token,请求参数:

  1. client_id:blog
  2. client_secret:blog
  3. grant_type:password
  4. username:admin
  5. password:admin

返回结果:

  1. {
  2. "access_token": "4aace702-cc9d-4a92-b507-9b65f192a65f",
  3. "token_type": "bearer",
  4. "refresh_token": "a50a6cff-97b0-4d0f-b3d2-e0fdcee6f142",
  5. "expires_in": 5591,
  6. "scope": "all user"
  7. }

资源访问

使用得到的access_token访问资源服务器中的/admin/hello接口,发送请求GET http://localhost:8080/blog-resource/admin/hello,请求头中携带参数:

Authorization:Bearer 4aace702-cc9d-4a92-b507-9b65f192a65f

返回结果:

  1. {
  2. "code": 200,
  3. "data": "Hello Admin"
  4. }
访问其他权限的接口,发送请求GET http://localhost:8080/blog-resource/user/hello,请求头中携带参数:
Authorization:Bearer 4aace702-cc9d-4a92-b507-9b65f192a65f

返回结果:

  1. {
  2. "code": 400,
  3. "message": "无权限访问"
  4. }

至此得到期望的访问结果,实现了统一权限控制

总结

  • SpringCloud Gateway使用WebFlux技术进行开发
  • SpringSecurity提供了@EnableWebFluxSecurity来支持WebFlux
  • SpringSecurity使用ReactiveSecurityContextHolder.getContext()来实现SecurityContextHolder功能

参考文档

联系方式

技术更新换代速度很快,我们无法在有限时间掌握全部知识,但我们可以在他人的基础上进行快速学习,学习也是枯燥无味的,加入我们学习牛人经验:

点击:加群讨论 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/68899
推荐阅读
相关标签
  

闽ICP备14008679号