如何在Spring资源服务器中解析自定义JWT并通过Redis验证权限
解决方案
1. 配置资源服务器解析自定义JWT字段
首先让Spring资源服务器能够解析JWT中的自定义authority字段,提取用户角色:
@Configuration @EnableResourceServer public class ResourceServerConfig { @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}") private String jwkSetUri; @Bean public JwtDecoder jwtDecoder() { return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build(); } @Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(jwt -> { List<Map<String, String>> authorities = jwt.getClaim("authority"); if (authorities == null || authorities.isEmpty()) { return Collections.emptyList(); } return authorities.stream() .map(auth -> new SimpleGrantedAuthority(auth.get("role"))) .collect(Collectors.toList()); }); return converter; } }
2. 实现Redis权限/限制校验组件
创建组件负责从Redis获取用户权限与限制数据,并完成校验逻辑:
@Component public class RedisPermissionValidator { private final StringRedisTemplate stringRedisTemplate; public RedisPermissionValidator(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate = stringRedisTemplate; } public boolean validate(String username) { List<String> permissionRestrictions = stringRedisTemplate.opsForList().range(username, 0, -1); if (permissionRestrictions == null || permissionRestrictions.isEmpty()) { return false; } // 优先检查是否存在限制项,存在则直接拒绝 boolean hasRestriction = permissionRestrictions.stream().anyMatch(item -> item.startsWith("Restriction")); if (hasRestriction) { return false; } // 检查是否存在有效权限项 return permissionRestrictions.stream().anyMatch(item -> item.startsWith("Permission")); } }
3. 自定义请求过滤器实现实时校验
添加自定义过滤器,在JWT认证完成后,提取用户信息并调用Redis校验组件,不符合条件则返回401:
@Component public class RedisAuthorizationFilter extends OncePerRequestFilter { private final RedisPermissionValidator permissionValidator; private final JwtDecoder jwtDecoder; public RedisAuthorizationFilter(RedisPermissionValidator permissionValidator, JwtDecoder jwtDecoder) { this.permissionValidator = permissionValidator; this.jwtDecoder = jwtDecoder; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); try { Jwt jwt = jwtDecoder.decode(token); String username = jwt.getSubject(); boolean isValid = permissionValidator.validate(username); if (!isValid) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("401 unauthorized"); return; } } catch (JwtException e) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("Invalid JWT token"); return; } } filterChain.doFilter(request, response); } }
4. 配置安全过滤链整合自定义过滤器
将自定义过滤器加入Spring Security过滤链,确保在JWT认证后执行校验:
@Configuration @EnableWebSecurity public class SecurityConfig { private final RedisAuthorizationFilter redisAuthorizationFilter; private final JwtAuthenticationConverter jwtAuthenticationConverter; private final JwtDecoder jwtDecoder; public SecurityConfig(RedisAuthorizationFilter redisAuthorizationFilter, JwtAuthenticationConverter jwtAuthenticationConverter, JwtDecoder jwtDecoder) { this.redisAuthorizationFilter = redisAuthorizationFilter; this.jwtAuthenticationConverter = jwtAuthenticationConverter; this.jwtDecoder = jwtDecoder; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .decoder(jwtDecoder) .jwtAuthenticationConverter(jwtAuthenticationConverter) ) ) .addFilterAfter(redisAuthorizationFilter, BearerTokenAuthenticationFilter.class); return http.build(); } }
关键说明
- JWT解析:通过
JwtAuthenticationConverter自定义提取authority字段中的角色,让Spring Security能识别用户身份角色。 - Redis校验逻辑:优先检查限制项,存在则直接拒绝请求;无限制时再校验是否存在有效权限,确保请求合法性。
- 过滤器顺序:将自定义过滤器放在
BearerTokenAuthenticationFilter之后,保证JWT完成认证后再执行Redis校验。
内容的提问来源于stack exchange,提问作者Vinayak Pattar
相关产品推荐
相关产品推荐

