java - 从 Spring Security 过滤器返回自定义 http 错误消息
问题描述
我正在构建一个 REST API,它使用 Spring Security(及其过滤器链)通过 JWT 对用户进行身份验证。现在,如果这样的 JWT 丢失、过期或类似情况,我想向 API 使用者返回格式正确的错误消息,而不是默认的白标签错误响应。从 Spring Security 过滤器返回的 API 错误消息应该与业务逻辑失败时返回的错误消息相同。
如果业务逻辑失败,我的 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"
}
我知道如果 Spring Security 过滤器链中发生错误,将永远无法到达控制器,因此我必须从安全过滤器中返回一条 HTTP 错误消息。我试过这样做:
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
添加):
Content-Type: application/json;charset=ISO-8859-1
{
"Simple": "Test"
}
我想简化这一点并使其保持一致。所以问题是,我怎样才能确定,只有
Content-Type: application/json
从安全过滤器返回?我尝试了很多选择,比如
response.setHeader("Content-Type", "application/json");
或者
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
但他们都没有工作。有任何想法吗?
解决方案
这种情况下的问题来自getWriter()
方法:
这个将默认字符编码包含到Response
将返回的 中,正如您在下一张图片中看到的那样,它会在返回Content-Type
的 中引发“附加信息” 。
当 Spring 序列化响应时,使用“getter 方法”,并且如您所见,getContentType
包括当前的charset
. 这就是您看到除了期望值之外的原因Content-Type
。
即使您尝试设置charset
一个null
值,它也不会起作用,因为该方法会检测到您正在使用 aWriter
并且它不会被更改(见下图)
但是,有一种方法可以实现您想要的:
} catch (JwtAuthorizationFailedException e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getOutputStream().print("{ \"Simple\": \"Test\" }");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
}
使用getOutputStream().print
代替getWriter().write
推荐阅读
- java - 计算谷数
- javascript - 更改 JavaScript 对象的结构
- javascript - 如何修复 process.nextTick 不是 Calgolia places.js 的功能?
- python - 如何创建有条件的热图?
- java - “Apache HTTP Server”中的配置“Content-Disposition 标头”
- c# - 管理谁连接到 ClickOnce 应用程序
- python - 如何从列表中更新 matplotlib 动画标题?
- javascript - 使用 Algolia places.js 库进行反向地理编码查询
- python - 在使用 Python 的 MySQL 查询中使用 %s 进行字符串格式化时出错
- javascript - 使用 javascript 显式关闭 xml 标签