[英]Spring security UsernamePasswordAuthenticationToken always returns 403: User credentials have expired
我正在嘗試在我的 kotlin 應用程序中實現基於 Spring 安全 JWT 的授權,但是在每個 /authenticate(登錄)上,即使返回 UsernamePassword3Token 的用戶憑據也已過期,但 UsernamePassword3Token: 用戶已找到用戶憑據。
安全配置 class:
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
class SecurityConfiguration(
private val userDetailsService: UserDetailService,
private val jwtAuthorizationFilter: JwtAuthorizationFilter,
) : WebSecurityConfigurerAdapter() {
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.cors().and()
.csrf().disable()
http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter::class.java)
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
@Bean
@Throws(Exception::class)
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
@Throws(Exception::class)
public override fun configure(auth: AuthenticationManagerBuilder) {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder())
}
@Bean
fun passwordEncoder() = BCryptPasswordEncoder()
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", CorsConfiguration().applyPermitDefaultValues())
return source
}
}
授權過濾器 class
@Component
class JwtAuthorizationFilter(
private val jwtUtil: JtwUtil,
private val userDetailsService: UserDetailsService) : OncePerRequestFilter() {
@Throws(IOException::class, ServletException::class)
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse,
filterChain: FilterChain
) {
val header = request.getHeader(SecurityConstants.TOKEN_HEADER)
if (StringUtils.isEmpty(header) || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
filterChain.doFilter(request, response)
return
}
val jwt: String = header.substring(7)
val username: String? = jwtUtil.extractUsername(jwt)
if (username != null && SecurityContextHolder.getContext().authentication == null) {
val userDetails: UserDetails = userDetailsService.loadUserByUsername(username)
val isValidToken: Boolean = jwtUtil.validateToken(jwt, userDetails)
if (isValidToken) {
val usernamePasswordAuthenticationToken =
UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
usernamePasswordAuthenticationToken.details =
WebAuthenticationDetailsSource().buildDetails(request)
SecurityContextHolder.getContext().authentication =
usernamePasswordAuthenticationToken
}
}
filterChain.doFilter(request, response)
}
}
用戶詳情服務:
@Service
class UserDetailService(private val userRepository: UserRepository): UserDetailsService {
override fun loadUserByUsername(username: String?): UserDetails? {
try {
val user: UserTable = userRepository.findByUsername(username)
?: throw UsernameNotFoundException("Username $username not found")
return AppUserDetails(user)
} catch (e: Exception) {
throw Exception(e)
}
}
這是我調用的 API 嘗試授權數據庫中的用戶
@RequestMapping("/api/authenticate")
@RestController
class AuthenticationController(
private val authenticationManager: AuthenticationManager,
private val userDetailsService: UserDetailsService,
private val userDetailService: UserDetailService,
private val jwtUtil: JtwUtil
) {
@PostMapping
fun authenticateUser(@RequestBody authenticationRequest: AuthenticationRequest):
ResponseEntity<AuthenticationResponse> {
try {
authenticationManager.authenticate
(UsernamePasswordAuthenticationToken(authenticationRequest.username,
authenticationRequest.password))
val userDetails: UserDetails =
userDetailsService.loadUserByUsername(authenticationRequest.username)
val jwt: String = jwtUtil.generateToken(userDetails)
return ResponseEntity.ok(AuthenticationResponse(jwt))
} catch (e: BadCredentialsException) {
throw BadCredentialsException("Incorrect username or password $e")
}
}
發現問題,可能對其他人有幫助。 在我的 UserDetails 服務中,我在 map 的用戶中硬編碼了該方法以始終返回 false
override fun isCredentialsNonExpired(): Boolean {
return false
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.