Spring Security 如何自定义@PreAuthorize(“isAuthenticated()”)返回的http状态?

bxgwgixi  于 11个月前  发布在  Spring
关注(0)|答案(2)|浏览(415)

在一个spring Boot 控制器中,我使用@PreAuthorize("isAuthenticated()")来检查用户是否登录(使用基本auth + JSESSIONID)。
但是如果用户没有登录,即他们没有经过身份验证,控制器将返回403 Forbidden
根据我所知道的身份验证与授权,401用于身份验证,而403用于授权。
根据我的理解,@PreAuthorize()总是检查用户的授权(顾名思义),但是有没有什么方法可以根据我们传递给它的参数来定制它,比如这里的isAuthenticated()
我知道还有另一种解决方案:在configure(HttpSecurity httpSecurity)中使用基于URL的安全配置,但如果我不想这样做呢?
任何想法请。

q1qsirdb

q1qsirdb1#

当你用@Pre/PostAuthorize注解方法A时,spring将为这样的对象创建代理,并且每个对这样的方法的调用都将通过代理(如果对象在spring上下文下)。
@Pre/PostAuthorize的代理将从annotation中评估expression(这里很复杂),如果为true,则将请求父对象(传递给真实的方法),如果不为true,则抛出抛出DanieledException。您也可以在方法A中自己抛出这样的异常,效果也是一样的。这里讲的是@Pre/PostAuthorize如何工作,没有更多的魔力!
但这不是故事的结局!
如果AccessDaniedException没有被抑制或重新转换(没有堆栈,堆栈中没有AccessDaniedException),那么它将被Spring Security中的ExceptionTranslationFilter捕获,ExceptionTranslationFilter将查看用户是否经过身份验证

  • 如果是,则ExceptionTranslationFilter将委托给AccessDeniedHandler来处理这种情况,AccessDeniedHandler的默认实现将返回403http代码或重定向到错误页面取决于您是否使用rest。
  • 如果没有,那么ExceptionTranslationFilter将委托给AuthenticationEntryPoint,它将处理这种情况(重定向到登录页面,要求http基本.等)。

注意:ExceptionTranslationFilter将重新抛出异常,如果任何其他AuthenticationExceptionAccessDeniedException和可能500将显示:(

您的问题可能是另一个问题,请查看Spring Security anonymous 401 instead of 403

被抑制:(:

@GetMapping(value = "/test/ok")
    public String getOk() {
        try {
            myService.securedMethod();
            return "ok";
        } catch (Exception e) {
            log.info("AccessDeniedException suppressed not rethrowing :(", e);
            return "error";
        }
    }

字符串
正确的重新翻译:):

@GetMapping(value = "/test/ok")
    public String getOk() {
        try {
            myService.securedMethod();
            return "ok";
        } catch (AccessDeniedException e) {
            throw new MyException(e); //public MyException(Throwable cause)
        }
    }

epggiuax

epggiuax2#

我也遇到了同样的问题,我用RestControllerAdviceExceptionHandler解决了这个问题

@ExceptionHandler(AccessDeniedException.class)
   public Response<ErrorResponse> exception(AccessDeniedException exception, HttpServletResponse response) {
       Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
       boolean isAuthenticated = !(authentication instanceof AnonymousAuthenticationToken);

       return error(
           isAuthenticated ? HttpStatus.FORBIDDEN.value() : HttpStatus.UNAUTHORIZED.value(),
           Collections.singleton(isAuthenticated ? exception.getMessage() : "Authentication is required"),
           exception,
           response
       );
   }

字符串

相关问题