当前位置: 首页 > 知识库问答 >
问题:

Spring Security中@PreAuthorize AccessDeniedException的错误处理返回500,而不是401

艾飞宇
2023-03-14

亲爱的,我喜欢在Spring4 Rest应用程序中自定义错误处理,所以如果控制器中的check in@preauthorize注释失败,它应该返回HTTP代码401,而不是服务器错误500。

@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() + "\" }");
   }
}

下面是我的身份验证FailureHandler:

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

这里是我的Spring Security配置

<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" />

这里是我的rest控制器类

@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);
}
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)`

共有1个答案

司寇飞航
2023-03-14

根据对另一篇文章的讨论(参见此处),我得出的结论是@PreAuthorize和authentication的错误处理使用了不同的概念。唯一的方法是在Spring3.2中使用带有@ControllerAdvision和@ExceptionHandler注释的通用错误处理程序的新概念。因此可以重用错误处理程序类。

@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() + "\" }");
  }
}
 类似资料:
  • 问题内容: 我有一个用PHP编写的页面。我无权访问服务器。我想这样做,而不是在PHP遇到错误时显示错误消息,而是给出500。 问题答案: 如果display_errors关闭,PHP 5.2默认会发送致命错误的HTTP 500。如果托管使用较旧的PHP,则必须注册自己的错误处理程序以及可能的异常处理程序,然后将用户重定向到您的500错误页面。尝试按照@Umang的建议在PHP脚本中设置displa

  • 我创建了一个C#ASP.NETCore6.0应用程序,并尝试使用Sustainsys使用Azure AD实现SSO。Saml2,特别是Sustainsys.Saml2.AspNetCore2软件包。在使用localhost在我的开发机器上测试了该实现之后,我可以看到它按预期工作,并对用户进行身份验证,填充身份模型,并重定向到正确的URL。 然而,当使用停靠版本部署到测试环境中时,行为会发生变化。触

  • 问题内容: 此JSON请求: 在某些情况下,将以以下形式带来500错误: 但是,这对我仍然有用,我需要能够正确处理此问题。 但是由于某种原因,当返回此500错误时,我的错误函数没有被调用,我在firebug中仅收到“ NetworkError:500 Internal Server Error”错误。 我该如何处理? 问题答案: 您是否尝试过像

  • 我有个例外 2018-11-01 21:05:49.122错误31446---[nio-8080-exec-1]O.A.C.C.C.[.[.[/].[dispatcherServlet]:servlet.Service()在路径[]上下文中的servlet[dispatcherServlet]引发异常[请求处理失败;嵌套异常为org.springframework.web.multipart.ma

  • 我部署基本Laravel项目到服务器。当我点击我的域名,它返回默认的欢迎视图。当我把简单的道路(见下文)添加到代码中,并尝试在浏览器中输入该路线时,它会返回500个内部错误。除"/"根路由外,所有路由都返回500错误。 文件夹结构: Laravel文件位于Laravel目录中,但来自公共目录的文件位于api目录中。 .api目录中的htaccess文件: 存储目录和其中的所有内容对任何人都是可写、

  • 我有一个spring boot webapp,我在其中定义了REST API。我将Spring Security性用于REST API安全性。 我已经用RESTController注释了我的控制器类。我最近更新了spring boot,mvc和安全性到最新版本。 我现在看到,在我的负面情况下,在更新之前,它返回json错误响应,但现在在更新之后,它返回html错误响应。 在更新之前,它给出了以下错