对于@PreAuthorized未身份验证请求,收到 Spring MVC AccessDeniedException 500 错误,而不是自定义 401 错误
2022-09-04 02:37:37
						我正在编写一个Java Spring MVC 4 REST应用程序,它将位于前端设备(网站,移动应用程序等)和数据库之间。我在下面有代码,它将为每个请求创建一个新会话(因为REST是无状态的),查看请求的授权标头,并将确认令牌有效并请求经过身份验证。
当用户在没有有效令牌的情况下请求安全方法时,我希望将未经授权的请求从 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);
    }
当我在没有授权标头的情况下运行该方法时,我收到此错误(而不是我想要获得的错误):
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
我不明白为什么我无法获得未经授权的请求来返回401 - 或500以外的任何其他状态代码。
你觉得怎么样?
 
					 
				 
				    		 
				    		 
				    		 
				    		