Spring Boot替换Filter

时间:2016-01-19 08:46:42

标签: json spring servlets spring-boot servlet-filters

我有一个Spring Boot Filter,我使用Jwt进行身份验证。如果成功,一切都很好,我发出了Json我的设计回复。但是,如果Authorization标头丢失或不正确,我会使用自定义消息抛出ServletException。这导致丑陋的Json看起来像这样:

{
   "timestamp":1453192910756,
   "status":500,
   "error":"Internal Server Error",
   "exception":"javax.servlet.ServletException",
   "message":"Invalid Authorization header.",
   "path":"/api/test"
}

我希望自定义此Json,因此我需要使用我所有其他回复的标准表单。

我的过滤器代码在这里:

public class JwtFilter extends GenericFilterBean {
    @Override
    public void doFilter(final ServletRequest req,
                         final ServletResponse res,
                         final FilterChain chain) throws IOException, ServletException {
        System.out.println("JwtFilter");
        final HttpServletRequest request = (HttpServletRequest) req;
        final String authHeader = request.getHeader("Authorization");
        if (authHeader == null) {
            throw new ServletException("Missing Authorization header.");
        }
        if (!authHeader.startsWith("Bearer ")) {
            throw new ServletException("Invalid Authorization header.");
        }
        final String token = authHeader.substring(7);
        try {
            final Claims claims = Jwts.parser().setSigningKey("secretkey")
                    .parseClaimsJws(token).getBody();
            request.setAttribute("claims", claims);
        }
        catch (final SignatureException e) {
            throw new ServletException("Invalid token.");
        }
        chain.doFilter(req, res);
    }
}

我尝试使用包装器来包装响应但是没有用。另一篇SO帖子说,回应并没有改变,但这甚至没有意义。

我认为正确的方法是修改ServletResponse res,但我无法让它发挥作用。

谢谢!

编辑:有点hacky但它​​有效。如果有更好的方法,请回答:

public class JwtFilter extends GenericFilterBean {
    @Override
    public void doFilter(final ServletRequest req,
                         final ServletResponse res,
                         final FilterChain chain) throws IOException, ServletException {
        System.out.println("JwtFilter");
        final HttpServletRequest request = (HttpServletRequest) req;
        final String authHeader = request.getHeader("Authorization");
        if (authHeader == null) {
            res.setContentType("application/json;charset=UTF-8");
            res.getWriter().write(ExceptionCreator.createJson("Missing Authorization header."));
            return;
        }
        if (!authHeader.startsWith("Bearer ")) {
            res.setContentType("application/json;charset=UTF-8");
            res.getWriter().write(ExceptionCreator.createJson("Invalid Authorization header."));
            return;
        }
        final String token = authHeader.substring(7);
        try {
            final Claims claims = Jwts.parser().setSigningKey("secretkey")
                    .parseClaimsJws(token).getBody();
            request.setAttribute("claims", claims);
        }
        catch (Exception f) {
            res.setContentType("application/json;charset=UTF-8");
            res.getWriter().write(ExceptionCreator.createJson("Invalid token."));
            return;
        }
        chain.doFilter(req, res);
    }
}

1 个答案:

答案 0 :(得分:1)

通常,在调用doFilter之后包装响应然后修改响应输出流是正确的方法,例如

PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper(
        (HttpServletResponse)response);
chain.doFilter(request, wrapper);
CharArrayWriter caw = new CharArrayWriter();
caw.write("your json");
response.setContentLength(caw.toString().getBytes().length);
out.write(caw.toString());
out.close();

取自Oracle JavaEE 5 Tutorial

尽管如此,您的用例似乎更适合在RestController处理程序方法中处理,可能与@ExceptionHandler(ServletException.class)带注释的方法一起使用。这将是一种更通用的方法,允许您利用Spring的内容协商功能来处理JSON序列化。