You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JWT签名不匹配:错误Token返回500而非401 Unauthorized

问题解决:错误JWT Token返回401 Unauthorized而非500错误

问题根源

当传入签名无效的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 18:32:13