从 Spring Security 过滤器返回自定义 http 错误消息 [英] Return custom http error message from Spring Security filter

查看:175
本文介绍了从 Spring Security 过滤器返回自定义 http 错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个 REST API,它使用 Spring Security(及其过滤器链)通过 JWT 对用户进行身份验证.现在,如果这样的 JWT 丢失、过期或类似,我想向 API 使用者返回一个格式良好的错误消息,而不是默认的白标签错误响应.从 Spring Security 过滤器返回的 API 错误消息应该与业务逻辑失败时返回的消息相同.

I am building a REST API that uses Spring Security (and it's filter chain) to authenticate the user via 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. 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 REST 控制器返回格式如下的错误消息(通过 @RestControllerAdvice):

In case of business logic failure, my Spring REST controllers return error messages that are formatted like this (via @RestControllerAdvice):

Content-Type: application/json

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

我知道如果 Spring Security 过滤器链中发生错误,控制器将永远无法到达,因此我必须从安全过滤器中返回 HTTP 错误消息.我试过这样做:

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. 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\" }");
        }

}

问题是,我得到的错误消息总是设置不同的 Content-Type 标头(添加了 charset=ISO-8859-1):

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: 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");

response.setContentType(MediaType.APPLICATION_JSON_VALUE);

但它们都不起作用.有什么想法吗?

but all of them did not work. Any ideas?

推荐答案

本例的问题来自于getWriter()方法:

The problem in this case comes from getWriter() method:

这个将默认字符编码包含到将返回的 Response 中,正如您在下一张图片中看到的,它会引发附加信息"返回的 Content-Type 内.

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.

当 Spring 序列化响应时,使用getter 方法";并且,如您所见,getContentType 包括当前的 charset.这就是为什么您会看到除了所需的 Content-Type 值之外的另一个值.

When Spring serialize the response, uses "getter methods" and, as you can see, getContentType includes the current charset. That is the reason you see that one besides desired Content-Type value.

即使您尝试将 charset 设置为 null 值,它也不会起作用,因为该方法会检测到您正在使用 Writer 并且不会改变(看下一张图片)

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)

但是,有一种方法可以实现您想要的:

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);
}

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

这篇关于从 Spring Security 过滤器返回自定义 http 错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆