2017-04-22 116 views
1

我正在寫一個Java Spring MVC的REST 4的應用程序,將前端設備(網站,移動應用等)和數據庫之間坐。我有下面的代碼,將爲每個請求創建一個新的會話(因爲REST是無狀態的),請查看請求的授權標頭,並確認令牌有效並請求驗證。Spring MVC的AccessDeniedException異常的500錯誤,而不是自定義401錯誤@PreAuthorized未授權的請求

當用戶請求一個安全的方法,沒有有效的令牌,我在尋找未授權的請求從500周重定向的訪問被拒絕的消息到401未授權消​​息。

這是我到目前爲止。

AccessDeniedHandler:

public class Unauthorized401AccessDeniedHandler implements AccessDeniedHandler { 
    @Override 
    public void handle(HttpServletRequest request, HttpServletResponse response, 
         AccessDeniedException accessDeniedException) 
      throws IOException, ServletException { 

     response.setStatus(401); 
    } 
} 

WebSecurityConfigurerAdapter:

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
       .sessionManagement() 
       .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
       .and() 
       .exceptionHandling() 
       .accessDeniedHandler(new Unauthorized401AccessDeniedHandler()); 

    } 
} 

篩選:

public class SecurityFilter implements Filter { 
    final static Logger logger = Logger.getLogger(SecurityFilter.class); 

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

     HttpServletRequest request = (HttpServletRequest) req; 
     HttpServletResponse response = (HttpServletResponse) res; 
     HttpSession session = request.getSession(); 

     String requestUri = request.getRequestURI(); 

     session.invalidate(); 
     SecurityContextHolder.clearContext(); 

     session = request.getSession(true); // create a new session 
     SecurityContext ctx = SecurityContextHolder.createEmptyContext(); 


     boolean isLoggedIn = false; 

     String token = null; 
     String authorizationHeader = request.getHeader("authorization"); 
     if(authorizationHeader != null && authorizationHeader.startsWith("bearer")) { 
      String encryptedToken = authorizationHeader.split(" ")[1]; 
      token = StringUtils.newStringUtf8(Base64.decodeBase64(encryptedToken)); 

      // confirm user is logged in and authorized here TBD 

      isLoggedIn = true; 
     } 

     PreAuthenticatedAuthenticationToken authentication = null; 
     if(isLoggedIn) { 
      SessionCredentialsModel authRequestModel = new SessionCredentialsModel(); 
      authRequestModel.employeeId = 323; 
      authRequestModel.firstName = "Danny"; 
      authRequestModel.lastName = "Boy"; 
      authRequestModel.token = "this_is_a_test_token"; 

      authentication = new PreAuthenticatedAuthenticationToken(authRequestModel, token); 
     } else { 
      authentication = new PreAuthenticatedAuthenticationToken(new SessionCredentialsModel(), null); 
     } 

     authentication.setAuthenticated(true); 
     ctx.setAuthentication(authentication); 

     SecurityContextHolder.setContext(ctx); 
     chain.doFilter(req, res); 
    } 

安全模型(又名安全上下文校長):

public class SessionCredentialsModel { 
    public int employeeId; 
    public String firstName; 
    public String lastName; 
    public String token; 

    public boolean isAuthenticated() { 
     if(employeeId > 0 && token != null) { 
      return true; 
     } 

     return false; 
    } 
} 

終於控制器:

@RequestMapping(value = "/", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) 
    @PreAuthorize("principal.isAuthenticated()") 
    public ResponseEntity<LoginResponseModel> create() { 
     LoginResponseModel responseModel = new LoginResponseModel(); 
     responseModel.statusCode = 55; 
     responseModel.token = "authorized model worked!"; 

     return new ResponseEntity<LoginResponseModel>(responseModel, HttpStatus.OK); 
    } 

當我運行的方法,無需Authorization頭我得到這個錯誤(而不是我希望得到錯誤):

HTTP Status 500 - Request processing failed; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied 

type Exception report 

message Request processing failed; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied 

description The server encountered an internal error that prevented it from fulfilling this request. 

exception 

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982) 
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648) 
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
    net.pacificentertainment.middletier.app.security.SecurityFilter.doFilter(SecurityFilter.java:73) 
root cause 

org.springframework.security.access.AccessDeniedException: Access is denied 
    org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) 
    org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) 
    org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) 
    net.pacificentertainment.middletier.app.controllers.EmployeeController$$EnhancerBySpringCGLIB$$b6765b64.create(<generated>) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    java.lang.reflect.Method.invoke(Method.java:498) 
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) 
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) 
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) 
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) 
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:648) 
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
    net.pacificentertainment.middletier.app.security.SecurityFilter.doFilter(SecurityFilter.java:73) 
note The full stack trace of the root cause is available in the Apache Tomcat/8.0.43 logs. 

Apache Tomcat/8.0.43 

我m,在虧損弄清楚爲什麼我不能讓未經授權的請求返回一個401 - 超過500

你認爲其他或任何其他狀態代碼?

回答

1

OK的傢伙,是不是能夠得到社會各界的幫助,但我沒有找到一個解決辦法 - 雖然它不是一個直接的解決方案。

@ControllerAdvice 
public class SecurityExceptionHandler extends ResponseEntityExceptionHandler { 

    @ExceptionHandler({AccessDeniedException.class}) 
    public ResponseEntity<Object> handleAccessDeniedException(Exception ex, WebRequest request) { 
     if(ex.getMessage().toLowerCase().indexOf("access is denied") > -1) { 
      return new ResponseEntity<Object>("Unauthorized Access", new HttpHeaders(), HttpStatus.UNAUTHORIZED); 
     } 

     return new ResponseEntity<Object>(ex.getMessage(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR); 
    } 
} 

我的應用程序中的這個新文件將允許我控制在異常期間發生的事情。現在,我可以手動檢查問題,看看它是否「訪問被拒絕」,然後重定向到401哪些工作。上面的問題是,重定向到401的代碼並沒有被擊中。這段代碼會被執行。

再次,這是不是我們操縱一條不同的Spring MVC的,善良的黑客默認行爲來得到它的工作有直接的解決方案。

如果有人有更優雅的解決方案,請張貼。

+0

它被解決了幾次例如:http://stackoverflow.com/a/22785514/4053082 –

相關問題