【问题标题】:Spring security JWT filter throws 500 and HTML instead of 401 and jsonSpring security JWT 过滤器抛出 500 和 HTML 而不是 401 和 json
【发布时间】:2020-11-04 06:33:00
【问题描述】:

我一直无法让安全系统正常工作,这个问题已经解决了一半 Spring Boot Security wont ignore certain paths that dont need to be secured 第二个问题是spring忽略了失败的HTTP状态码,总是抛出500。

当 JWT 令牌无效时,我想返回 401 和 json 响应。我不断得到一个 500 和白色标签的 html 页面。 JwtFilter

class JwtFilter(private val tokenService: TokenService) : GenericFilterBean() {

    override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {

        val request = req as HttpServletRequest
        val response = res as HttpServletResponse

        val httpRequest = request as HttpServletRequest
        val path = httpRequest.servletPath.toString().substring(0, 12)
        if (path == "/api/v1/auth") {
            chain.doFilter(req, res)
            return
        } else {
            val token = TokenUtil.extractToken(request as HttpServletRequest)

            if (token != null && token.isNotEmpty()) {
                try {
                    tokenService.getClaims(token)
                } catch (e: SignatureException) {
                    throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid JWT Signature")
                } catch (e: MalformedJwtException) {
                    throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid JWT token")
                } catch (e: ExpiredJwtException) {
                    throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Expired JWT token")
                } catch (e: UnsupportedJwtException) {
                    throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Unsupported JWT exception")
                } catch (e: IllegalArgumentException) {
                    throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Jwt claims string is empty")
                }
            } else {
                throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing auth token")
            }
            chain.doFilter(req, res)
        }
    }
}

在我的应用程序类中我也有

@SpringBootApplication(exclude = [ErrorMvcAutoConfiguration::class])

应用程序中的其他任何地方 ResponseStatusException 都会以正确的代码和 JSON 格式抛出错误,例如,当我抛出异常时,响应将是 HTML 之类的

HTTP 状态 500 – 内部服务器错误 身体 { 字体系列:Tahoma、Arial、无衬线字体; }

    h1,
    h2,
    h3,
    b {
        color: white;
        background-color: #525D76;
    }

    h1 {
        font-size: 22px;
    }

    h2 {
        font-size: 16px;
    }

    h3 {
        font-size: 14px;
    }

    p {
        font-size: 12px;
    }

    a {
        color: black;
    }

    .line {
        height: 1px;
        background-color: #525D76;
        border: none;
    }
</style>

HTTP 状态 500 – 内部服务器错误

类型异常报告

消息 401 UNAUTHORIZED "Expired JWT token"

描述 服务器遇到了一个意外情况,导致它无法完成请求。

异常

org.springframework.web.server.ResponseStatusException: 401 UNAUTHORIZED "Expired JWT token"
    events.slap.app.web.security.JwtFilter.doFilter(JwtFilter.kt:40)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
    org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)

注意服务器日志中提供了根本原因的完整堆栈跟踪。

Apache Tomcat/9.0.35

【问题讨论】:

  • 我仍然不明白您为什么要编写自己的过滤器和 oauth 支持。它在 Spring/Spring Boot 中都是开箱即用的。授权服务器,如果你是强迫症,在重写时暂时被弃用(大多数人认为这很愚蠢——重写它,然后弃用旧版本哈哈)。 Imo,仍然没有理由编写自己的与经过实战测试的解决方案。您还可以使用 Keycloak 等。

标签: spring spring-boot spring-security


【解决方案1】:

不要在过滤器中抛出异常,而是这样做

    response.sendsetStatus(HttpServletResponse.SC_UNAUTHORIZED);  
    return;

或者如果你也想要消息

    StringBuilder sb = new StringBuilder();
    sb.append("{ ");
    sb.append("\"error\": \"Unauthorized\" ");
    sb.append("\"message\": \"Unauthorized\"");<--- your message here
    sb.append("\"path\": \"")
      .append(request.getRequestURL())
      .append("\"");
    sb.append("} ");

    response.setContentType("application/json");
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);  
    response.getWriter().write(sb.toString());
    return;

【讨论】:

  • 这工作正常!但我认为那将是 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
【解决方案2】:

这个问题困扰了我三天左右,感谢@Kavithakaran Kanapathippillai 的评论。

我的做法是这样的

        if (token != null && token.isNotEmpty()) {
            String msg = new String();
            try {
                tokenService.getClaims(token)
            } catch (SignatureException ex) {
            msg = "Invalid JWT signature";
            } catch (MalformedJwtException ex) {
            msg = "Invalid JWT token";
            } catch (ExpiredJwtException ex) {
            msg = "Expired JWT token";
            } catch (UnsupportedJwtException ex) {
            msg = "Unsupported JWT token";
            } catch (IllegalArgumentException ex) {
            msg = "JWT claims string is empty.";
            }
        if (msg.isNotEmpty()) {
            StringBuilder sb = new StringBuilder();
            sb.append("{ ");
            sb.append("\"error\": \"Unauthorized\",");
            sb.append("\"message\": \"Invalid Token.\",");
            sb.append("\"path\": \"")
            .append(request.getRequestURL())
            .append("\"");
            sb.append("} ");
            response.setContentType("application/json");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write(sb.toString());
            return;
        }
        chain.doFilter(req, res)

【讨论】:

    【解决方案3】:

    如果您正在设置 SecurityWebFilterChain 使用的 ServerAuthenticationEntryPoint(与 @EnableWebFluxSecurity 一起提供),您可以使用它

    class  HttpBasicServerAuthenticationEntryPoint implements ServerAuthenticationEntryPoint
    

    由于某种原因,当我尝试实现自己的入口点时,我得到了 500 而不是 401。但是,它按预期工作,现在抛出 401。

    【讨论】:

      猜你喜欢
      • 2021-06-21
      • 2018-09-04
      • 2021-07-24
      • 1970-01-01
      • 2017-09-12
      • 2015-08-19
      • 2015-10-13
      • 2020-01-04
      • 2018-11-06
      相关资源
      最近更新 更多