简体   繁体   English

从 Spring Security 过滤器返回自定义 http 错误消息

[英]Return custom http error message from Spring Security filter

I am building a REST API that uses Spring Security (and it's filter chain) to authenticate the user via JWT.我正在构建一个 REST API,它使用 Spring Security(及其过滤器链)通过 JWT 对用户进行身份验证。 Now, if such a JWT is missing, expired or similar, I would like to return a nicely formatted error message to the API consumer, instead of the default whitelabel error response.现在,如果这样的 JWT 丢失、过期或类似,我想向 API 使用者返回一个格式良好的错误消息,而不是默认的白标签错误响应。 The API error messages returned out of the Spring Security filter should look identical to the ones returned in case of business logic failure.从 Spring Security 过滤器返回的 API 错误消息应该与业务逻辑失败时返回的相同。

In case of business logic failure, my Spring REST controllers return error messages that are formatted like this (via @RestControllerAdvice ):在业务逻辑失败的情况下,我的 Spring REST 控制器返回格式如下的错误消息(通过@RestControllerAdvice ):

Content-Type: application/json

{
  "code": "VOUCHER_NOT_FOUND",
  "message": "The specified voucher code was not found.",
  "timestamp": "2020-09-06T21:22:23.015Z"
}

I understand that if an error happens in the Spring Security filter chain, controllers will never be reached, so I have to return an HTTP error message out of the security filter.我知道如果 Spring Security 过滤器链中发生错误,控制器将永远无法到达,因此我必须从安全过滤器中返回 HTTP 错误消息。 I've tried to do this like this:我试过这样做:

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    @Override
    protected final void doFilterInternal(final HttpServletRequest request,
            final HttpServletResponse response, final FilterChain chain)
            throws IOException, ServletException {
        try {
            // Perform various auth checks here
            // Throw JwtAuthorizationException if a check fails
            chain.doFilter(request, response);
        } catch (JwtAuthorizationFailedException e) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setHeader("Content-Type", "application/json");  // does not work
            response.getWriter().write("{ \"Simple\": \"Test\" }");
        }

}

The problem is, that the resulting error message I get, always sets a different Content-Type header (with charset=ISO-8859-1 added):问题是,我得到的结果错误消息总是设置不同的Content-Type标头(添加了charset=ISO-8859-1 ):

Content-Type: application/json;charset=ISO-8859-1

{
  "Simple": "Test"
}

I would like to streamline this and make it consistent.我想简化它并使其保持一致。 So the question is, how can I make sure, only所以问题是,我怎样才能确保,只有

Content-Type: application/json

is returned from the security filter?从安全过滤器返回? I've tried numerous options, like我尝试了很多选择,比如

response.setHeader("Content-Type", "application/json");

or或者

response.setContentType(MediaType.APPLICATION_JSON_VALUE);

but all of them did not work.但所有这些都不起作用。 Any ideas?有任何想法吗?

The problem in this case comes from getWriter() method:这种情况下的问题来自getWriter()方法:

获取写入器()

This one includes the default character encoding into the Response that will be returned and, as you can see in the next picture, it provokes the "additional information" inside the returned Content-Type .这将默认字符编码包含到将返回的Response中,正如您在下一张图片中所见,它会在返回的Content-Type引发“附加信息”。

获取内容类型

When Spring serialize the response, uses "getter methods" and, as you can see, getContentType includes the current charset .当 Spring 序列化响应时,使用“getter 方法”,并且如您所见, getContentType包括当前charset That is the reason you see that one besides desired Content-Type value.这就是您看到除所需Content-Type值之外的其他值的原因。

Even if you try to set charset with a null value, it won't work because the method will detect you are using a Writer and it won't be changed ( see next picture )即使您尝试使用null值设置charset ,它也不会起作用,因为该方法会检测您正在使用Writer并且不会更改它(见下图

设置字符编码

However, there is a way to achieve what you want:但是,有一种方法可以实现您想要的:

} catch (JwtAuthorizationFailedException e) {
  response.setStatus(HttpStatus.UNAUTHORIZED.value());
  response.getOutputStream().print("{ \"Simple\": \"Test\" }");
  response.setContentType(MediaType.APPLICATION_JSON_VALUE);
}

Use getOutputStream().print instead of getWriter().write使用getOutputStream().print而不是getWriter().write

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM