【问题标题】:Spring Security ignoring access-denied-handler with Method Level SecuritySpring Security 忽略具有方法级安全性的访问拒绝处理程序
【发布时间】:2014-02-05 22:56:46
【问题描述】:

我正在使用 Spring 3.2.4 并且在使用基于注释的方法级别安全性时无法让 Spring Security 重定向到我的access-denied-handler。我找到了几个关于此的不同帖子,但到目前为止,我似乎没有找到任何解决方案。

我的 security.xml 文件:

<!-- need this here to be able to secure methods in components other than controllers (as scanned in applicationContext.xml) -->
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled" ></global-method-security>

<!-- Annotation/JavaConfig examples http://stackoverflow.com/questions/7361513/spring-security-login-page -->
<http use-expressions="true" entry-point-ref="authenticationEntryPoint">
    <access-denied-handler ref="accessDeniedHandler"/>

    <intercept-url pattern="/secure/login" access="permitAll" />
    <intercept-url pattern="/secure/logout" access="permitAll" />
    <intercept-url pattern="/secure/denied" access="permitAll" />
    <session-management session-fixation-protection="migrateSession" session-authentication-error-url="/login.jsp?authFailed=true"> 
        <concurrency-control max-sessions="10" error-if-maximum-exceeded="true" expired-url="/login.html" session-registry-alias="sessionRegistry"/>
    </session-management>

    <intercept-url pattern="/**" access="isAuthenticated()" />
    <form-login  default-target-url="/" authentication-failure-url="/secure/denied" />
    <logout logout-url="/secure/logout" logout-success-url="/" />
    <expression-handler ref="defaultWebSecurityExpressionHandler" />
</http>

<beans:bean id="authenticationEntryPoint" class="com.ia.security.LoginUrlAuthenticationEntryPoint">
    <beans:constructor-arg name="loginFormUrl" value="/secure/login"/>
</beans:bean>

<beans:bean id="accessDeniedHandler" class="com.ia.security.AccessDeniedHandlerImpl">
    <beans:property name="errorPage" value="/secure/denied"/>
</beans:bean>

我的 AccessDeniedHandlerImpl.java :

public class AccessDeniedHandlerImpl extends org.springframework.security.web.access.AccessDeniedHandlerImpl {
    // SLF4J logger
    private static final Logger logger = LoggerFactory.getLogger(AccessDeniedHandlerImpl.class);

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        logger.log("AccessDeniedException triggered!");
        super.handle(request, response, accessDeniedException);

    }
}

我的注释方法:

@PreAuthorize("hasAuthority('ROLE_ZZZZ')")
public ModelAndView getUserInfo( @PathVariable long userId ){
    ModelAndView mv = new ModelAndView();
    User u = userService.findUser( userId );
    mv.addObject("user", u);
    return mv;
}

我需要做些什么特别的事情才能调用我的拒绝访问处理程序吗?

【问题讨论】:

    标签: spring-mvc spring-security


    【解决方案1】:

    经过几个小时的搜索和跟踪 Spring 代码,我终于发现了发生了什么。我在这里列出它以防它对其他人有价值。

    access-denied-handlerExceptionTranslationFilter 使用,以防AccessDeniedException。但是,org.springframework.web.servlet.DispatcherServlet 首先尝试处理异常。具体来说,我有一个用defaultErrorView 定义的org.springframework.web.servlet.handler.SimpleMappingExceptionResolver。因此,SimpleMappingExceptionResolver 通过重定向到适当的视图来消耗异常,因此,没有任何异常可以冒泡到 ExceptionTranslationFilter

    修复相当简单。配置SimpleMappingExceptionResolver忽略所有AccessDeniedException

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="uncaughtException" />
        <property name="excludedExceptions" value="org.springframework.security.access.AccessDeniedException" />
    
        <property name="exceptionMappings">
            <props>
                <prop key=".DataAccessException">dataAccessFailure</prop>
                <prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
                <prop key=".TypeMismatchException">resourceNotFound</prop>
                <prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
            </props>
        </property>
    </bean>
    

    现在,每当抛出 AccessDeniedException 时,解析器都会忽略它并允许它将堆栈冒泡到 ExceptionTranslationFilter,然后调用 access-denied-handler 来处理异常。

    【讨论】:

    • 我还没有得到。正如你所描述的那样,我也遇到了这个问题,但还没有得到:(
    • 这个配置的javaconfig?
    • @Eric 你能分享一下这个解决方案的 Java 配置吗?
    • @mav3n 我从来没有为这个解决方案编写 Java Config,但考虑到它只是一个简单的 bean 定义,我无法想象它太难了。当时(在 Spring 3 中),Java Config 需要比 Spring 5 中的某些类更多的工作。我建议只查看 SimpleMappingExceptionResolver 中不同方法的签名,并确保尊重正确的类类型。
    • @Eric,是的,我找到了 java 配置,但在我的情况下,这似乎不是问题。由于其他一些具有更高顺序优先级的 ControllerAdvice,我的 ControllerAdvice 没有被调用。感谢您的回复。
    【解决方案2】:

    我遇到了同样的问题。在我的情况下,已经定义了一个应该处理异常的 @ControllerAdvise - 所以我直接添加了 AccessDeniedException:

    @Component
    @ControllerAdvice
    public class ControllerBase {
    
    ...
    
      @ExceptionHandler(value = AccessDeniedException.class)
        public ModelAndView accessDenied() {
            return new ModelAndView("redirect:login.html");
        }
    }
    

    祝你好运!

    【讨论】:

      【解决方案3】:

      使用SimpleMappingExceptionResolver 的JavaConfig 扩展Eric 答案以忽略AccessDeniedException,以便它可以作为响应抛出并且不会被SimpleMappingExceptionResolver 吞噬。

      @Configuration
      @EnableWebMvc
      public class AppConfig extends WebMvcConfigurerAdapter {
      
        @Bean
        public SimpleMappingExceptionResolver exceptionResolver() {
          SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
          exceptionResolver.setExcludedExceptions(AccessDeniedException.class);
          return exceptionResolver;
        }
      
      }
      

      【讨论】:

        【解决方案4】:

        添加到上面的 Jessi 答案 (https://stackoverflow.com/a/25948861/13215486)。请注意,如果您想区分访问被拒绝和访问被禁止,那么您需要做更多的工作。

        @Component
        @ControllerAdvice
        public class ControllerBase {
        
        ...
        
          @ExceptionHandler(value = AccessDeniedException.class)
            public ModelAndView accessDenied(HttpServletRequest request) {
                ModelAndView mav = new ModelAndView("redirect:login.html");
                mav.setStatus(request.getRemoteUser() != null ? HttpStatus.FORBIDDEN : HttpStatus.UNAUTHORIZED);
                return mav;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2013-10-31
          • 2011-12-26
          • 2014-05-08
          • 1970-01-01
          • 1970-01-01
          • 2020-02-21
          • 2013-08-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多