2017-04-26 93 views
0

我對Spring安全級別上的異常有疑問。ExceptionHandler前置控制器過濾器(Spring Security)

我使用SM_USER標頭進行授權,並驗證請求是否通過DelegateRequestMatchingFilter(它有助於瞭解是否需要SM_USER)。

的問題是,如果在所有的線沒有SM_USER頭super.doFilter(...)拋出一個PreAuthenticatedCredentialsNotFoundException不能與標準ExceptionResolver處理的控制器,這就是爲什麼看起來很奇怪,並從所有應用程序拋出的其他異常不同。

我試圖寫一個自己的方法,標記爲@ExceptionResolver註釋爲過濾器,但它被忽略。

如何爲此過濾器插入ExceptionsResolver?

DelegateRequestMatchingFilter片斷

public class DelegateRequestMatchingFilter extends RequestHeaderAuthenticationFilter { 

private RequestMatcher ignoredRequests; 
public DelegateRequestMatchingFilter(RequestMatcher matcher) { 
    super(); 
    super.setPrincipalRequestHeader("SM_USER"); 
    this.ignoredRequests = matcher; 
} 

@Override 
public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException { 

    HttpServletRequest httpReq = (HttpServletRequest) req;  
    if(ignoredRequests.matches(httpReq)) { 
     chain.doFilter(req,resp); 
    } else { 
     super.doFilter(req,resp,chain);//<-- throws exception 
    }  
} 
} 

片段從ExceptionResolver,因爲它僅適用於控制器

@ControllerAdvice 
public class ExceptionResolver extends AbstractHandlerExceptionResolver{ 


@Override 
protected ModelAndView doResolveException(HttpServletRequest request, 
     HttpServletResponse responce, Object handler, Exception exception) { 

    ModelAndView toReturn = new ModelAndView(); 
    toReturn.setView(new MappingJackson2JsonView()); 
    toReturn.addObject("message", exception.getMessage()); 
    toReturn.addObject("exceptionClass", exception.getClass().getCanonicalName()); 
    return toReturn; 
} 

@ExceptionHandler(PreAuthenticatedCredentialsNotFoundException.class)  
public ResponseEntity<Result> handleBindException(PreAuthenticatedCredentialsNotFoundException e) { 

    Result result = new Result("the identification header is missing"); 
    result.setException(PreAuthenticatedCredentialsNotFoundException.class); 
    ResponseEntity<Result> response = new ResponseEntity<Result>(result, HttpStatus.FORBIDDEN); 
    return response; 
} 
} 

SecurityConfiguration

不解決問題

如果我根據答案更改我的代碼,我得到這個例外,甚至SM_USER頭存在並且是正確的

org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource 
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.java:177) 
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:133) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:168) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) 
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) 
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) 
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) 
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) 
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221) 
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) 
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) 
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) 
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) 
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) 
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) 
at org.eclipse.jetty.server.Server.handle(Server.java:497) 
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310) 
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) 
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540) 
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) 
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) 
at java.lang.Thread.run(Thread.java:745) 
+0

可能是彈簧層頂部的過濾器,這就是爲什麼它不工作 –

+0

@VinitSolanki,也許。問題是我如何使它工作。 – user2957954

回答

1

首先,你需要加入濾光片ExceptionTranslationFilter後,該過濾器將處理AccessDeniedExceptionAuthenticationException當它捕捉它們。

http.addFilterAfter(siteMinderFilter(), ExceptionTranslationFilter.class); 

和未來需要注入AuthenticationEntryPoint處理AuthenticationException,還有一些已經存在AuthenticationEntryPoint你可以使用它,就像HttpStatusEntryPointLoginUrlAuthenticationEntryPoint,...;

如果你想回到你需要實現自己的AuthenticationEntryPoint JSON響應,例如:

public class ExampleAuthenticationEntryPoint implements AuthenticationEntryPoint { 

    private static final Logger logger = LoggerFactory.getLogger(ExampleAuthenticationEntryPoint.class); 

    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 
     logger.error(authException.getMessage(), authException); 
     if (!response.isCommitted()) { 
      Map<String, Object> responseMsg = new HashMap<String, Object>(); 
      responseMsg.put("message", authException.getMessage()); 
      ObjectMapper mapper = new ObjectMapper(); 
      try { 
       response.setContentType("application/json;charset=utf-8"); 
       response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
       PrintWriter writer = response.getWriter(); 
       writer.write(mapper.writeValueAsString(responseMsg)); 
       writer.flush(); 
       writer.close(); 
      } catch (IOException e) { 
       // ignore 
       logger.error(e.getMessage(), e); 
      } 
     } 
    } 
} 

我覺得這是更好地返回HTTP雕像代碼401代替403403用於AccessDeniedException;

然後注入您自己的AuthenticationEntryPointExceptionTranslationFilter;

http.exceptionHandling().authenticationEntryPoint(myEntryPoint()); 

@Bean 
AuthenticationEntryPoint myEntryPoint() { 
    return new ExampleAuthenticationEntryPoint(); 
} 

/* 
Or just return 401 
AuthenticationEntryPoint myEntryPoint() { 
    return new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED); 
} 
*/ 

BTW:

如果您在RequestHeaderAuthenticationFilter設置continueFilterChainOnUnsuccessfulAuthenticationtrue,該異常不會在超級過濾器扔,它的默認值是true,也許你需要將其設置爲false,否則你會需要在DelegateRequestMatchingFilter中注入AuthenticationFailureHandler來處理執行身份驗證時的異常。

**更新**

else if (exception instanceof AccessDeniedException) { 
      Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
      if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) { 
       logger.debug(
         "Access is denied (user is " + (authenticationTrustResolver.isAnonymous(authentication) ? "anonymous" : "not fully authenticated") + "); redirecting to authentication entry point", 
         exception); 

       sendStartAuthentication(
         request, 
         response, 
         chain, 
         new InsufficientAuthenticationException(
           "Full authentication is required to access this resource")); 
      } 
      else { 
       logger.debug(
         "Access is denied (user is not anonymous); delegating to AccessDeniedHandler", 
         exception); 

       accessDeniedHandler.handle(request, response, 
         (AccessDeniedException) exception); 
      } 
     } 

正如你可以從代碼讀,現在是AccessDeniedException,我覺得你可以禁用匿名用戶,或者您需要檢查爲什麼你AccessDeniedException

http.anonymous().disable();

更新2

Authentication currentUser = SecurityContextHolder.getContext() 
      .getAuthentication(); 

    if (currentUser == null) { 
     return true; 
    } 

    if (!checkForPrincipalChanges) { 
     return false; 
    } 

    if(!principalChanged(request, currentUser)) { 
     return false; 
    } 

checkForPrincipalChanges默認值是false,所以現在如果啓用anon過濾器,這將返回false,並跳過RequestHeaderAuthenticationFilter做認證,所以只是嘗試禁用anon過濾器。你需要學習Spring的安全代碼並通過調試來研究它。

+0

謝謝,它的作品! – user2957954

+0

沒有。這是行不通的。他拋出了exery請求的異常。 – user2957954

+0

你能發佈更多信息嗎?異常堆棧? – chaoluo

相關問題