微服务OAuth 2.1认证授权Demo方案(Spring Security 6)
书接上文
微服务OAuth 2.1认证授权可行性方案(Spring Security 6)
一、介绍
三个微服务
auth微服务作为认证服务器,用于颁发JWT。gateway微服务作为网关,用于拦截过滤。content微服务作为资源服务器,用于校验授权。
以下是授权相关数据库。
user表示用户表role表示角色表user_role关联了用户和角色,表示某个用户是是什么角色。一个用户可以有多个角色menu表示资源权限表。@PreAuthorize("hasAuthority('xxx')")时用的就是这里的code。permission关联了角色和资源权限,表示某个角色用于哪些资源访问权限,一个角色有多个资源访问权限。
当我们知道userId,我们就可以知道这个用户可以访问哪些资源,并把这些权限(也就是menu里的code字段)写成数组,写到JWT的负载部分的authorities字段中。当用户携带此JWT访问具有@PreAuthorize("hasAuthority('xxx')")修饰的资源时,我们解析出JWT中的authorities字段,判断是否包含hasAuthority指定的xxx权限,以此来完成所谓的的”授权”。
二、auth微服务代码
1. SecurityConfig
1 | package com.xuecheng.auth.config; |
这里需要注意几点
- 使用
BCryptPasswordEncoder密码加密,在设置clientSecret时需要手动使用密码编码器。 jwtTokenCustomizer解析UserDetails然后往JWT中添加authorities字段,为了后面的授权。
2. UserDetailsService
1 | package com.xuecheng.ucenter.service.impl; |
这里需要注意几点
username就是前端/auth/login的时候输入的账户名。myAuthService.execute(username)不抛异常,就默认表示账户存在,此时将password加入UserDetails并返回,Spring Authorization Server对比校验两个密码。myAuthService.execute(username)根据username获取用户信息返回,将用户信息存入withUsername中,Spring Authorization Server默认会将其加入到JWT中。- 现在
Spring Authorization Server默认不会把authorities(permissions)写入JWT,需要配合OAuth2TokenCustomizer手动写入。
3. 总结
这样,auth微服务颁发的JWT,现在就会包含authorities字段。示例如下
1 | { |
三、gateway微服务代码
1. 统一处理CORS问题
1 | @EnableWebFluxSecurity |
这里需要注意几点
- 书接上文,这里虽然用了
oauth2.jwt(Customizer.withDefaults()),但实际上基于远程auth微服务开放的jwkSetEndpoint配置的JwtDecoder。 .cors(cors -> cors.configurationSource(corsConfigurationSource()))一次性处理CORS问题。
四、content微服务代码
1. controller
1 | @PreAuthorize("hasAuthority('xc_teachmanager_course_list')") |
使用了@PreAuthorize("hasAuthority('xc_teachmanager_course_list')")修饰的controller资源。
2. SecurityConfig
1 | @Configuration |
需要注意几点
- 使用
@EnableMethodSecurity让@PreAuthorize生效 - 和
gateway一样,需要基于远程auth微服务开放的jwkSetEndpoint配置JwtDecoder。 - 指定
JwtAuthenticationConverter,让anyRequest().authenticated()需要验证的请求,除了完成默认的JWT验证外,还需要完成JwtAuthenticationConverter指定逻辑。 JwtAuthenticationConverter中将JWT的authorities部分形成数组后写入GrantedAuthorities,这正是spring security6用于校验@PreAuthorize的字段。
3. 解析JWT Utils
1 | @Slf4j |
把JWT的信息解析回XcUser ,相当于用户携带JWT访问后端,后端可以根据JWT获取此用户的信息。当然,你可以尽情的自定义,扩展。
4. 总结
当用户携带JWT访问需要权限的资源时,现在可以正常的校验权限了。
五、一些坑
- 写
RegisteredClient时注册那么多redirectUri是因为debug了很久,才发现获取授权码和获取JWT时,redirect_uri参数需要一致。 cors问题,spring secuity6似乎会一开始直接默认拒绝cors,导致跨域请求刚到gateway就寄了,到不了content微服务,即使content微服务配置了CORS的处理方案,也无济于事。
微服务OAuth 2.1认证授权Demo方案(Spring Security 6)
https://xiamu-ssr.github.io/Hexo/2024/02/13/2024-H1/2024-02-13-23-00-26/

