Spring Security 5.7如何正确注册OncePerRequestFilter校验Token
Spring Security JWT 权限配置问题
需求说明
我正在通过提供登录、刷新端点的AuthController实现简易Web服务权限管控,规则如下:
/auth/**路径开放匿名访问- 其余所有API仅在携带有效Token时才可访问
目前认证端点本身逻辑可正常运行,但安全配置存在异常:将JwtTokenFilter添加到安全配置后,向auth/login路径发送POST请求时出现连接拒绝错误;同时将JwtTokenFilter声明为Bean后,无法断点调试进入filterChain执行逻辑,初步判断是过滤器的实现或注册方式存在错误。
初始实现代码
JwtTokenFilter 代码
class JwtTokenFilter() : OncePerRequestFilter() { @Autowired private lateinit var jwtTokenService: JwtTokenService @Autowired private lateinit var refreshTokenService: RefreshTokenService @Autowired private lateinit var userDetailService: UserDetailService override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain ) { val jwt = jwtTokenService.getTokenFromAuthHeader(request) jwt?.let { token -> try { val claims = jwtTokenService.getClaimsFromToken(token) val userDetails = userDetailService.loadUserByUsername(claims.subject) val authentication = UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities) authentication.details = WebAuthenticationDetailsSource().buildDetails(request) SecurityContextHolder.getContext().authentication = authentication refreshTokenService.updateRefreshToken(claims.subject) } catch (ex: Exception) { logger.warn("JWT-Token <$token> invalid token") } } logger.trace("API request to <${request.requestURI}> with token <${!jwt.isNullOrEmpty()}>") filterChain.doFilter(request, response) } }
初始WebSecurityConfig配置代码
@Configuration @EnableWebSecurity(debug = true) @EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) class WebSecurityConfig() { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http.authorizeHttpRequests() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated() http.csrf().disable() http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter::class.java) return http.build() } @Bean fun jwtTokenFilter(): JwtTokenFilter { return JwtTokenFilter() } @Bean fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? { return authenticationConfiguration.authenticationManager } @Bean fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } }
调整后的WebSecurityConfig配置
针对上述问题我更新了WebSecurityConfig配置,改为构造器注入依赖、新增无状态会话配置,调整后代码如下:
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) @EnableWebSecurity(debug = true) @Configuration class WebSecurityConfig( private val jwtTokenService: JwtTokenService, private val refreshTokenService: RefreshTokenService, private val userDetailService: UserDetailService ) { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http .csrf().disable() http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) http.authorizeHttpRequests() .antMatchers("/auth/**").permitAll() http.authorizeHttpRequests() .anyRequest().authenticated() //http.apply(MyCustomDsl.customDsl(jwtTokenService, userDetailService, refreshTokenService)) http.addFilterBefore(JwtTokenFilter(jwtTokenService, userDetailService, refreshTokenService), UsernamePasswordAuthenticationFilter::class.java) return http.build() } @Bean fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? { return authenticationConfiguration.authenticationManager } @Bean fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } /* class MyCustomDsl( private val jwtTokenService: JwtTokenService, private val userDetailService: UserDetailService, private val refreshTokenService: RefreshTokenService, ) : AbstractHttpConfigurer<MyCustomDsl, HttpSecurity>() { companion object { fun customDsl(jwtTokenService: JwtTokenService,userDetailService: UserDetailService, refreshTokenService: RefreshTokenService): MyCustomDsl { return MyCustomDsl(jwtTokenService, userDetailService, refreshTokenService) } } override fun configure(http: HttpSecurity) { http.addFilterBefore(JwtTokenFilter(jwtTokenService, userDetailService, refreshTokenService), UsernamePasswordAuthenticationFilter::class.java) } }*/ }
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

