2016-05-16 72 views
0

我在我的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);會因各種原因而AuthenticationExceptionAuthenticationException是一個自定義異常,它可以延伸到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

這個'AuthenticationException'是你的自定義異常還是spring的'AuthenticationException'? –

+0

這是我自己的自定義異常類 – Gregg

回答

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

catchreturn聲明是這樣在doFilter方法結束我的chain.doFilter(request, response);不叫。