【问题标题】:ExceptionMappingAuthenticationFailureHandler not catching my exceptionExceptionMappingAuthenticationFailureHandler 没有捕捉到我的异常
【发布时间】:2015-11-21 09:22:57
【问题描述】:

在我使用 Spring Security 保护的 Spring MVC 应用程序中,我必须使用多种登录方式:一种是通过识别特定授权 IP 列表(不需要用户/密码登录),另一种是通过经典登录。为此,我构建了一个自定义身份验证提供程序来验证 IP 是否被授权。如果不是,我希望它重定向到通知用户的错误页面。

在这种情况下,我会抛出异常 (org.springframework.security.authentication.InsufficientAuthenticationException),我正在尝试使用 ExceptionMappingAuthenticationFailureHandler 来捕获它并重定向到正确的页面。失败处理程序将InsufficientAuthenticationException 映射到该页面,并将BadCredentialsException 映射到另一个错误页面(在执行经典用户/密码登录并且登录错误时使用)。

我检查了我实际上是在抛出异常的日志。但是,故障处理程序永远不会捕获它;相反,我总是得到用于BadCredentialsException 的页面。 如何确保我抛出的异常被失败处理程序捕获?

这是我的 security-context.xml 的摘录:

<http
    auto-config="true"
    use-expressions="true">
    <form-login
        login-page="/pages/login.jsp"
        login-processing-url="/j_spring_security_check"
        default-target-url="/"
        authentication-failure-handler-ref="authenticationFailureHandler" />
</http>

<beans:bean
    id="customIPAddressAuthenticationProvider"
    class="ch.of.ow.security.CustomIPAddressAuthenticationProvider" />

<beans:bean
    id="authenticationFailureHandler"
    class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
    <beans:property name="exceptionMappings">
        <beans:props>
            <beans:prop 
                key="org.springframework.security.authentication.InsufficientAuthenticationException">
                /notValidIP
            </beans:prop> <!-- THIS IS THE PAGE I WANT -->
            <beans:prop 
                key="org.springframework.security.authentication.BadCredentialsException">
                /pages/login.jsp?login_error=true
            </beans:prop>  <!-- THIS IS THE PAGE I GET INSTEAD -->
        </beans:props>
    </beans:property>
</beans:bean>


 <authentication-manager alias="authenticationManager">
    <authentication-provider ref="customIPAddressAuthenticationProvider" />
    <authentication-provider user-service-ref='userDetailsService'>
    <password-encoder hash="bcrypt" />
    </authentication-provider>
 </authentication-manager>

这里是 CustomIPAddressAuthenticationProvider 的相关部分:

public class CustomIPAddressAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException, InsufficientAuthenticationException {
        if (!authentication.getPrincipal().equals("") || !authentication.getCredentials().equals("")) {
            // if the user did provide a username/password, skip to the next
            // authentication provider, as he will want to log in with his
            // credentials instead of his IP
            return null;
        }
        WebAuthenticationDetails wad = null;
        String userIPAddress = null;
        boolean isAuthenticatedByIP = false;

        // Get the IP address of the user tyring to use the site
        wad = (WebAuthenticationDetails) authentication.getDetails();
        userIPAddress = wad.getRemoteAddress();
        // Check if the user is authorized
        isAuthenticatedByIP = ipIsAuthorized(userIPAddress); //the ipIsAuthorized does its stuff well

        // Authenticated, the user's IP address is authorized
        if (isAuthenticatedByIP) {
            List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
            Authentication result = new UsernamePasswordAuthenticationToken("xxxxxxxxx", "yyyyyyyyy", grantedAuths);
            return result;
        } else {
            System.out.println("Going to throw InsufficientAuthenticationException");
            throw new InsufficientAuthenticationException(userIPAddress);
        }
    }

}

我还注意到,如果我删除了失败处理程序的第二个映射,我只留下了:

            <beans:prop 
                key="org.springframework.security.authentication.InsufficientAuthenticationException">
                /notValidIP
            </beans:prop>

然后我看到,如果我尝试使用不受信任的 IP 进行访问,我会收到来自 /j_spring_security_checkHTTP Status 401 - Authentication Failed: Bad credentials。所以这确实是个例外。我可能把我的异常扔错了地方吗?在身份验证提供程序中抛出异常是否意味着触发链中更高级别的错误凭据异常?

提前感谢您提供的任何建议。

【问题讨论】:

    标签: java spring spring-mvc authentication spring-security


    【解决方案1】:

    好的,我想通了。如果您有多个身份验证提供程序,Spring 的ProviderManager 会负责遍历它们,直到找到一个提供有效身份验证的提供程序。 如果您像我一样在其中一个提供程序中抛出异常,ProviderManager 将捕获它;但是,除非异常是 AccountStatusExceptionInternalAuthenticationServiceException 的实例(或子类),它只会在提供者列表中继续。这个看ProviderManager的源码就很清楚了。

    在我的例子中,这意味着当我抛出InsufficientAuthenticationException(它既不是AccountStatusException 也不是InternalAuthenticationServiceException 的子类)时,ProviderManager 会不停地接住它并继续前进到userDetailsService提供者;由于没有输入登录信息,这将始终导致 BadCredentialsException,然后会出现在 ExceptionMappingAuthenticationFailureHandler 中。

    解决办法是:

    • 创建一个扩展DisabledExceptionIPNotTrustedException
    • IPNotTrustedException 扔进我的CustomIPAddressAuthenticationProvider
    • IPNotTrustedException 映射到我想要访问的/notValidIP URL。

    当然,不要忘记将/notValidIP 设置为无需身份验证即可访问。奇迹般有效。 :)

    【讨论】:

      猜你喜欢
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多