2017-04-16 26 views
1

私はSpring 4 Restアプリケーションでエラー処理をカスタマイズしたいので、チェックインの際にはServer Error 500を返さなければなりません@コントローラのPreAuthorizeアノテーションが失敗します。@PreAuthorizeのためのSpring SecurityでのErrorHandling AccessDeniedExceptionではなく、500を返す401

私は独自のAuthenticationEntryPointとAuthenticationFailureHandlerを登録して、その開始/エラー処理メソッドは401を返します。これはJWT認証には問題ありませんが、 "AccessDeniedException"で@PreAuthorizeチェックが失敗した場合、 springはサーバーエラー500を返します。

どのようにカスタマイズできますか?私は何かを逃したように見える?事前のヒントはありがとうございます。ここで

私AuthenticationEntryPointクラス:

@Component 
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { 
    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {  
    response.setContentType("application/json"); 
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
    response.getOutputStream().println("{ \"error\": \"" + authException.getMessage() + "\" }"); 
    } 
} 

ここに私のAuthenticationFailureHandler:ここ

public class JWTAuthenticationFailureHandler implements AuthenticationFailureHandler { 
    @Override 
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 
    response.sendError(401, (new StringBuilder()).append("Authentication Failed: ").append(exception.getMessage()).toString()); 
    } 
} 

ここに私の春のセキュリティ設定

<security:global-method-security pre-post-annotations="enabled"/> 

<security:http pattern="/api/**" entry-point-ref="restAuthenticationEntryPoint" > 
    <security:csrf disabled="true"/> 
    <security:intercept-url pattern="/api/**" access="isAuthenticated()" /> 
    <security:custom-filter ref="authenticationTokenProcessingFilter" before="FORM_LOGIN_FILTER" /> 
</security:http> 

<security:authentication-manager alias="authenticationManager"> 
    <security:authentication-provider ref="jwtAuthenticationProvider" /> 
</security:authentication-manager> 

<bean id="restAuthenticationEntryPoint" class="ch.megloff.common.webservice.jwt.RestAuthenticationEntryPoint"/> 

<bean id="authenticationTokenProcessingFilter" class="ch.megloff.common.webservice.jwt.JWTAuthenticationFilter"> 
    <constructor-arg type="java.lang.String"><value>/api/**</value></constructor-arg> 
    <property name="authenticationManager" ref="authenticationManager"></property> 
    <property name="authenticationFailureHandler" ref="jwtAuthenticationFailureHandler" /> 
</bean> 

<bean id="jwtAuthenticationProvider" class="ch.megloff.common.webservice.jwt.JWTAuthenticationProvider" /> 
<bean id="jwtAuthenticationFailureHandler" class="ch.megloff.common.webservice.jwt.JWTAuthenticationFailureHandler" /> 

私の残りのコントローラクラス

@RestController 
public class UserController { 

    @Autowired 
    private UserService userService; 

    @PreAuthorize("hasAuthority('admin')") 
    @RequestMapping(value = "/api/user/", method = RequestMethod.GET) 
    public ResponseEntity<List<User>> listAllUsers(HttpServletRequest request, HttpServletResponse response) { 
    System.out.println("Fetching all Users"); 
    List<User> users = userService.getUsers(); 
    if(users.isEmpty()){ 
     return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT); 
    } 
    return new ResponseEntity<List<User>>(users, HttpStatus.OK); 
} 

ここで注釈で@PreAuthorizeチェックに失敗したサーバーからのスタックトレース:別のポストの議論に基づいて

SEVERE: Servlet.service() for servlet [myusers] in context with path [/JWTAuthenticationExample] threw exception [Request processing failed; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied] with root cause 
org.springframework.security.access.AccessDeniedException: Access is denied 
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) 
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) 
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) 
at ch.megloff.myusers.UserController$$EnhancerBySpringCGLIB$$635caa86.listAllUsers(<generated>) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:498) 
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220) 
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) 
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) 
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) 
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) 
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:720) 
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466) 
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391) 
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318) 
at org.springframework.security.web.firewall.RequestWrapper$FirewalledRequestAwareRequestDispatcher.forward(RequestWrapper.java:154) 
at ch.megloff.common.webservice.jwt.JWTAuthenticationSuccessHandler.onAuthenticationSuccess(JWTAuthenticationSuccessHandler.java:23) 
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:326) 
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:240) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) 
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) 
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) 
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) 
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) 
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) 
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217) 
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) 
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) 
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) 
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) 
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) 
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) 
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673) 
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) 
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
at java.lang.Thread.run(Thread.java:745)` 

答えて

3

hereを参照してください)私は、エラーがためにハンドリングという結論になりました@ PreAuthorizeと認証は異なる概念を使用します。唯一の方法は、@ControllerAdviceと@ExceptionHandlerアノテーションを持つgeneric error handlerの新しいコンセプトを春に使用することです。したがって、エラーハンドラクラスを再利用することができます。

@Component 
@ControllerAdvice 
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { 
    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {  
    response.setContentType("application/json"); 
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
    response.getOutputStream().println("{ \"error\": \"" + authException.getMessage() + "\" }"); 
    } 

    @ExceptionHandler(value = { AccessDeniedException.class }) 
    public void commence(HttpServletRequest request, HttpServletResponse response, AccessDeniedException ex) throws IOException { 
    response.setContentType("application/json"); 
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
    response.getOutputStream().println("{ \"error\": \"" + ex.getMessage() + "\" }"); 
    } 
} 
+0

また、のような応答でエラーを設定することによってこれを行うことができます 'response.sendError(HttpServletResponse.SC_UNAUTHORIZED、ex.getMessage());' –

関連する問題