使用弹簧安全特别登录

2022-09-03 02:09:36

我目前工作的公司有一种特殊的身份验证过程。

实际上,多个用户可以具有相同的登录名和密码。因此,要识别它们,在第二次中,用户必须提供他的电子邮件。但同样,在少数情况下,可能会担心几个用户,然后,用户必须提供他的公司ID才能完全进行身份验证。

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

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

提前致谢。


答案 1

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

希望下面的代码能提供一些关于如何针对你的方案解决它的良好提示。

创建自定义用户详细信息检查器以处理身份验证后检查。这是确定用户角色的位置。

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"));
            }
    }

创建自定义身份验证成功处理程序。此类根据用户的角色将用户发送到正确的 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);
}

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

<security:authentication-manager>
    <security:authentication-provider ref="customAuthenticationProvider" />
</security:authentication-manager>

<bean id="customAuthenticationProvider" class="YourAuthenticationProvider">
    <property name="postAuthenticationChecks">
        <bean class="CustomPostAuthenticationChecks"/>
    </property>
</bean>

如果您使用的是标准表单登录标记,则可以轻松地定义自定义身份验证成功处理程序:

<security:form-login authentication-success-handler-ref="customAuthenticationSuccessHandler">

...

<bean id="customAuthenticationSuccessHandler" class="CustomAuthenticationSuccessHandler"/>

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

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

答案 2

推荐