JWT签名不匹配:错误Token返回500而非401 Unauthorized
问题根源
当传入签名无效的JWT Token时,Jwts.parserBuilder().parseClaimsJws(token)会抛出SignatureException,但当前JwtTokenFilter仅捕获了IllegalArgumentException和ExpiredJwtException,未处理该异常,导致异常向上传播触发500服务器错误,而非预期的401未授权响应。
修复方案
1. 扩展JwtTokenFilter的异常捕获范围
修改JwtTokenFilter的doFilterInternal方法,添加对SignatureException、MalformedJwtException等JWT验证失败异常的捕获,并在捕获后直接返回401响应。
修改后的JwtTokenFilter代码:
import io.jsonwebtoken.ExpiredJwtException import io.jsonwebtoken.MalformedJwtException import io.jsonwebtoken.SignatureException import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.web.authentication.WebAuthenticationDetailsSource import org.springframework.stereotype.Component import org.springframework.web.filter.OncePerRequestFilter import java.io.IOException import javax.servlet.FilterChain import javax.servlet.ServletException import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse @Component class JwtTokenFilter( private val jwtUserDetailsService: JwtUserDetailsService, private val jwtTokenUtil: JwtTokenUtil ) : OncePerRequestFilter() { @Throws(ServletException::class, IOException::class) override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain ) { val requestTokenHeader = request.getHeader("Authorization") var username: String? = null var jwtToken: String? = null if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) { jwtToken = requestTokenHeader.substring(7) try { username = jwtTokenUtil.getUsernameFromToken(jwtToken) } catch (e: IllegalArgumentException) { logger.error("无法获取JWT Token", e) sendUnauthorizedResponse(response, "无效的JWT Token") return } catch (e: ExpiredJwtException) { logger.error("JWT Token已过期", e) sendUnauthorizedResponse(response, "JWT Token已过期") return } catch (e: SignatureException) { logger.error("JWT签名验证失败", e) sendUnauthorizedResponse(response, "JWT签名无效") return } catch (e: MalformedJwtException) { logger.error("JWT Token格式错误", e) sendUnauthorizedResponse(response, "JWT Token格式无效") return } } else { logger.warn("JWT Token未以Bearer开头") } if (username != null && SecurityContextHolder.getContext().authentication == null) { val userDetails: UserDetails = jwtUserDetailsService.loadUserByUsername(username) if (jwtTokenUtil.validateToken(jwtToken, userDetails)) { val authToken = UsernamePasswordAuthenticationToken( userDetails, null, userDetails.authorities ) authToken.details = WebAuthenticationDetailsSource().buildDetails(request) SecurityContextHolder.getContext().authentication = authToken } else { sendUnauthorizedResponse(response, "Token验证失败") return } } chain.doFilter(request, response) } private fun sendUnauthorizedResponse(response: HttpServletResponse, message: String) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message) } }
2. 优化JwtTokenUtil的validateToken方法
在validateToken方法中增加异常捕获,避免验证时抛出未处理的异常:
fun validateToken(token: String?, userDetails: UserDetails): Boolean { return try { val username = getUsernameFromToken(token) username == userDetails.username && !isTokenExpired(token) } catch (e: Exception) { logger.error("Token验证失败", e) false } }
3. 确认AuthenticationEntryPoint配置
当前的JwtException(即AuthenticationEntryPoint)配置正确,会在未携带Token或认证失败时返回401,扩展异常捕获后可覆盖所有JWT验证失败场景。
验证效果
传入错误签名、过期、格式无效的JWT Token时,接口会直接返回401 Unauthorized响应,不再抛出500服务器错误。
内容的提问来源于stack exchange,提问作者Pauline
相关产品推荐
相关产品推荐

