Spring security AccessDeniedHandler 不被调用

1.问题

在使用Spring Security时,在applicationContext-security.xml中配置了accecc-denied-handler:

	<!-- 自动配置模式,拦截所有请求,有ROLE_USER才可以通过  -->
	<http auto-config="true" >

		<intercept-url pattern="/login**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
		<intercept-url pattern="/js/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />

		<intercept-url pattern="/**" access="ROLE_USER" /> 

		<form-login login-page="/login.html" authentication-failure-url ="/loginfailure" default-target-url="/loginsuccess"/>
		<logout invalidate-session="true" logout-success-url="/login.html" logout-url="/j_spring_security_logout"/>

		<span style="background-color: rgb(255, 0, 0);"><strong><access-denied-handler ref="myAuthenticationFailureHandler"/></strong></span>

	</http>

    <beans:bean id="myAuthenticationFailureHandler" class="com.lenovo.MyAuthenticationFailureHandler" />

而且AccessDecisionManager模块明明抛出了AccessDeniedException:

public class MyAccessDecisionManager implements AccessDecisionManager {

    /**
     * @author ligh4 2015年3月31日下午5:28:21
     */
    @Override
    public void decide(Authentication arg0, Object arg1, Collection<ConfigAttribute> arg2)
            throws AccessDeniedException {

        if (arg2 == null) {
            return;
        }
        LogHelper.debug(this, arg1.toString()); //object is a URL.
        Iterator<ConfigAttribute> ite = arg2.iterator();
        while (ite.hasNext()) {
            ConfigAttribute ca = ite.next();
            String needRole = ((SecurityConfig) ca).getAttribute();
            for (GrantedAuthority ga : arg0.getAuthorities()) {
                if (needRole.equals(ga.getAuthority())) { //ga is user's role.
                    return;
                }
            }
        }
<strong><span style="color:#FF0000;">        LogHelper.warn(this, "No right of url:" + arg1.toString());
        throw new AccessDeniedException("no right");</span></strong>

    }

    /**
     * @author ligh4 2015年3月31日下午5:28:21
     */
    @Override
    public boolean supports(ConfigAttribute arg0) {
        // TODO Auto-generated method stub
        return true;
    }

    /**
     * @author ligh4 2015年3月31日下午5:28:21
     */
    @Override
    public boolean supports(Class<?> arg0) {
        // TODO Auto-generated method stub
        return true;
    }

}

但是MyAuthenticationFailureHandler中却无法捕获该异常:

/**
 * 类 MyAuthenticationFailureHandler 的实现描述:TODO 类实现描述
 *
 * @author ligh4 2015年3月31日下午4:04:40
 */
public class MyAuthenticationFailureHandler implements AccessDeniedHandler {

    /**
     * @author ligh4 2015年3月31日下午4:15:59
     */
    @Override
    public void handle(HttpServletRequest arg0, HttpServletResponse arg1, AccessDeniedException arg2)
            throws IOException, ServletException {

        LogHelper.debug(this, "handler AccessDeniedException...");

        HttpServletRequest httpRequest = arg0;
        // is ajax request?
        if ("XMLHttpRequest".equals(httpRequest.getHeader("X-Requested-With"))) {
            String msg = "{\"success\" : false, \"message\" : \"authentication-failure\"}";

            arg1.setContentType("json");
            OutputStream outputStream = arg1.getOutputStream();
            outputStream.write(msg.getBytes());
            outputStream.flush();
        }
    }

}

2.原因

参考:http://stackoverflow.com/questions/7013197/spring-3-security-accessdeniedhandler-is-not-being-invoked

原文内容如下:

AccessDeniedHandler is invoked when user is logged in and there is no permissions to resource (source
here
). If you want to handle request for login page when user is not logged in, just configure in
security-context:

<http ... entry-point-ref="customAuthenticationEntryPoint">

And define customAuthenticationEntryPoint:

<beans:bean id="customAuthenticationEntryPoint" class="pl.wsiadamy.webapp.controller.util.CustomAuthenticationEntryPoint">
</beans:bean>


TIP, don‘t try to fight with ExceptionTranslationFilter.I have tried to override
org.springframework.security.web.access.ExceptionTranslationFilter, without effects:

<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
  <beans:property name="authenticationEntryPoint"  ref="customAuthenticationEntryPoint"/>
  <beans:property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</beans:bean>
<beans:bean id="accessDeniedHandler"
 class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
  <beans:property name="errorPage" value="/accessDenied.htm"/>
</beans:bean>

The ref="customAuthenticationEntryPoint" just didn‘t invoked.

就是说只有确实的访问失败才会进入AccessDeniedHandler,如果是未登陆或者会话超时等,不会触发AccessDeniedHandler,而是会直接跳转到登陆页面。具体可参见ExceptionTranslationFilter中的处理:

doFilter函数:

<span style="color:#000000;">public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            chain.doFilter(request, response);

            logger.debug("Chain processed normally");
        }
        catch (IOException ex) {
            throw ex;
        }
        catch (Exception ex) {
            // Try to extract a SpringSecurityException from the stacktrace
            Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
            RuntimeException ase = (AuthenticationException)
                    throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);

            if (ase == null) {
                ase = (AccessDeniedException)throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
            }

            if (ase != null) {
                <strong><span style="color:#FF0000;">handleSpringSecurityException(request, response, chain, ase);</span></strong>
            } else {
                // Rethrow ServletExceptions and RuntimeExceptions as-is
                if (ex instanceof ServletException) {
                    throw (ServletException) ex;
                }
                else if (ex instanceof RuntimeException) {
                    throw (RuntimeException) ex;
                }

                // Wrap other Exceptions. This shouldn't actually happen
                // as we've already covered all the possibilities for doFilter
                throw new RuntimeException(ex);
            }
        }
    }</span>

handleSpringSecurityException函数:

<span style="color:#000000;">private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            RuntimeException exception) throws IOException, ServletException {
        if (exception instanceof AuthenticationException) {
            logger.debug("Authentication exception occurred; redirecting to authentication entry point", exception);

            sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
        }
        else if (exception instanceof AccessDeniedException) {
            <strong><span style="color:#FF0000;">if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication()))</span></strong> {
                logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
                            exception);

                <strong><span style="color:#FF0000;">sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException(
                        "Full authentication is required to access this resource"));</span></strong>
            }
            else {
                logger.debug("Access is denied (user is not anonymous); delegating to AccessDeniedHandler", exception);

                accessDeniedHandler.handle(request, response, (AccessDeniedException) exception);
            }
        }
    }</span>

根本不会调用accessDeniedHandler,而是转入验证页面(也就是登陆页面)。

所以使用时还是要注意区分登陆失败和没有权限访问的情况。

时间: 2024-10-06 15:19:35

Spring security AccessDeniedHandler 不被调用的相关文章

Spring Security(14)——权限鉴定基础

目录 1.1     Spring Security的AOP Advice思想 1.2     AbstractSecurityInterceptor 1.2.1    ConfigAttribute 1.2.2    RunAsManager 1.2.3    AfterInvocationManager Spring Security的权限鉴定是由AccessDecisionManager接口负责的.具体来说是由其中的decide()方法负责,其定义如下. void decide(Authe

spring security oauth2.0 实现

oauth应该属于security的一部分.关于oauth的的相关知识可以查看阮一峰的文章:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 一.目标 现在很多系统都支持第三方账号密码等登陆我们自己的系统,例如:我们经常会看到,一些系统使用微信账号,微博账号.QQ账号等登陆自己的系统,我们现在就是要模拟这种登陆的方式,很多大的公司已经实现了这种授权登陆的方式,并提供了相应的API,供我们开发人员调用.他们实际上用的也规范是oauth2.0

[转]Spring Security学习总结一

[总结-含源码]Spring Security学习总结一(补命名空间配置) Posted on 2008-08-20 10:25 tangtb 阅读(43111) 评论(27)  编辑  收藏 所属分类: Spring .Spring Security Spring Security学习总结一 在认识Spring Security之前,所有的权限验证逻辑都混杂在业务逻辑中,用户的每个操作以前可能都需要对用户是否有进行该项 操作的权限进行判断,来达到认证授权的目的.类似这样的权限验证逻辑代码被分散

(一)关于spring security的简要介绍以及相关配置和jar包认识

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. 安全主要包括两个操作,"认证和验证(权限控制)"

Spring Security(09)——Filter

目录 1.1     Filter顺序 1.2     添加Filter到FilterChain 1.3     DelegatingFilterProxy 1.4     FilterChainProxy 1.5     Spring Security定义好的核心Filter 1.5.1    FilterSecurityInterceptor 1.5.2    ExceptionTranslationFilter 1.5.3    SecurityContextPersistenceFilt

使用Spring Security和OAuth2实现RESTful服务安全认证

这篇教程是展示如何设置一个OAuth2服务来保护REST资源. 源代码下载github. (https://github.com/iainporter/oauth2-provider)你能下载这个源码就开始编写一个被OAuth方法保护的服务.该源码包含功能: * 用户注册和登录* Email验证* Password 丢失 采取的技术有以下: * OAuth2 Protocol * spring Security * Spring Integration * Spring Data * Jerse

Spring security 3.x 普通login与ajax login笔记

原创文章,欢迎转载!转载时务必保留:作者:jmppok ;出处http://blog.csdn.net/jmppok/article/details/44832641 1.问题 在一个Web项目中一般会有两部分组成: 1)静态资源, 如html页面, js脚本,图片等等. 2)API接口. 在进行权限控制时,需要对这两部分进行统一管理. Spring框架本身提供了强大的Security机制,但是在使用过程中还是会出现以下问题: 当用户访问一个页面时,页面本身经常是既包含静态资源,又需要调用API

Spring Security 梳理 - DelegatingFilterProxy

可能你会觉得奇怪,我们在web应用中使用Spring Security时只在web.xml文件中定义了如下这样一个Filter,为什么你会说是一系列的Filter呢? <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class&g

spring security使用和原理简析(1)

主要参考:https://blog.csdn.net/u012373815/article/details/55225079 源码参考:https://github.com/527515025/springBoot 项目需求 1:实现了用户.角色.权限的动态管理,可以管控到接口地址,已经访问方式(get,post) 2:自定义登录接口 3:结合spring-session,来保存用户登录信息 表结构说明 method来控制相同方法名的不同访问方式(get,post,put等) 项目结构 废话不多