我在spring-boot
应用程序中实现了一些基于令牌的身份验证。我有一个过滤器,在该过滤器中,我正在执行以下操作:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader("X-TOKEN-AUTH");
String username = null;
if (securityEnabled) {
if (authToken != null) {
try {
username = userTokenService.validateToken(authToken);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities());
auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (AuthenticationException ae) {
//TODO log something about signature exception
log.warn(ae.getMessage());
}
}
}
chain.doFilter(request, response);
}
我还有一个自定义的AuthFailureHandler:
@Component
public class AuthFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter writer = response.getWriter();
writer.write(exception.getMessage());
writer.flush();
}
}
由于各种原因,我的代码username = userTokenService.validateToken(authToken);
会抛出AuthenticationException
。 AuthenticationException
是一个扩展Exception
的自定义异常。当我捕获此异常时,我仍然希望返回401,但我希望我的消息显示在当前作为JSON发送的Spring Security
默认情况下:
{
"timestamp": 1463408604943,
"status": 401,
"error": "Unauthorized",
"message": "An Authentication object was not found in the SecurityContext",
"path": "/api/brands/2"
}
我想要,例如......
{
"timestamp": 1463408604943,
"status": 401,
"error": "Unauthorized",
"message": "Invalid Token: Expired",
"path": "/api/brands/2"
}
我不确定如何覆盖此行为。
答案 0 :(得分:0)
所以......我终于想通了。问题是过滤器在食物链上的位置越来越高,所以他们实际上并没有那么多涉及Spring。我在Filter中抛出异常的地方,Spring并不一定能抓住它。过滤器只会抛出500并显示异常消息。要修复它,我只需要在过滤器中捕获我的异常,然后使用适当的http状态调用sendError
。
try {
username = userTokenService.validateToken(authToken);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities());
auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(auth);
chain.doFilter(request, response);
return;
} catch (Exception ex) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage());
return;
}
return
中的catch
语句是为了不调用chain.doFilter(request, response);
方法末尾的doFilter
。