有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用Spring Security的java特殊登录

我目前工作的公司有一种特殊的认证流程

实际上,几个用户可以拥有相同的登录名和密码。因此,为了识别他们,用户必须在第二次发送电子邮件。但是,在少数情况下,可能会涉及多个用户,然后用户必须提供其公司id以进行完全身份验证

因此,我的问题是,在某些情况下,身份验证过程不能一步完成,这是Spring Security开箱即用处理的大多数应用程序的默认行为

所以我的问题是:用Spring Security实现这个特殊登录过程的最简单方法是什么

提前谢谢


共 (1) 个答案

  1. # 1 楼答案

    我必须做一个类似的两步认证过程。这听起来很简单,但找到正确的注入位置和覆盖方法并不容易。其基本思想是为中间身份验证(电子邮件检查)提供另一个角色,然后在确认电子邮件后授予完全访问权限

    希望下面的代码能为您的场景提供一些很好的提示

    创建自定义UserDetailsChecker以处理身份验证后检查。这是决定用户角色的地方

    public class CustomPostAuthenticationChecks implements UserDetailsChecker {
    
            public void check(UserDetails userDetails) {
    
                CustomUser customUser = (CustomUser) userDetails;
                if (customUser.needsEmailAuthentication()) {
                    // Get rid of any authorities the user currently has
                    userDetails.getAuthorities().clear();
                    // Set the new authority, only allowing access to the 
                    // email authentication page.
                    userDetails.getAuthorities().add(new GrantedAuthorityImpl("ROLE_NEEDS_EMAIL_AUTH"));
                } else {
                    userDetails.getAuthorities().add(new GrantedAuthorityImpl("ROLE_AUTHORIZED_USER"));
                }
        }
    

    创建自定义AuthenticationSuccessHandler。此类根据用户的角色将用户发送到正确的URL

    public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    
    @Override
    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
    
        String targetUrl = null;
    
        SecurityContext securityContext = SecurityContextHolder.getContext();
    
        Collection<GrantedAuthority> authorities = securityContext.getAuthentication().getAuthorities();
    
        if (authorities.contains(new GrantedAuthorityImpl("ROLE_NEEDS_EMAIL_AUTH"))) {
            targetUrl = "/authenticate";
        } else if (authorities.contains(new GrantedAuthorityImpl("ROLE_AUTHORIZED_USER"))) {
            targetUrl = "/authorized_user_url";
        } else {
            targetUrl = super.determineTargetUrl(request, response);
        }
    
        return targetUrl;
    }
    

    用户的电子邮件地址经过身份验证后,您需要授予用户对应用程序的完全访问权限:

    public void grantUserAccess(User user) {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication auth = securityContext.getAuthentication();
        user.getAuthorities().clear();
        user.getAuthorities().add(new GrantedAuthorityImpl("ROLE_AUTHORIZED_USER"));
        Authentication newAuth = new UsernamePasswordAuthenticationToken(user, auth.getCredentials(), user.getAuthorities());
        securityContext.setAuthentication(newAuth);
    }
    

    定义自定义身份验证提供程序以注册CustomPostAuthenticationChecks:

    <security:authentication-manager>
        <security:authentication-provider ref="customAuthenticationProvider" />
    </security:authentication-manager>
    
    <bean id="customAuthenticationProvider" class="YourAuthenticationProvider">
        <property name="postAuthenticationChecks">
            <bean class="CustomPostAuthenticationChecks"/>
        </property>
    </bean>
    

    如果您使用的是标准表单登录标记,则可以轻松定义自定义AuthenticationSuccessHandler:

    <security:form-login authentication-success-handler-ref="customAuthenticationSuccessHandler">
    
    ...
    
    <bean id="customAuthenticationSuccessHandler" class="CustomAuthenticationSuccessHandler"/>
    

    /authenticateURL添加新的角色拦截规则,以便只有需要更多验证的用户才能访问该页面

    <security:intercept-url pattern="/authenticate/**" access="hasRole('ROLE_NEEDS_EMAIL_AUTH')" />
    <security:intercept-url pattern="/authorized_user_url/**" access="hasRole('ROLE_AUTHORIZED_USER')" />