强制用户在 Spring Security 中更改过期密码

Posted

技术标签:

【中文标题】强制用户在 Spring Security 中更改过期密码【英文标题】:Forcing user to change expired password in spring security 【发布时间】:2012-01-18 04:51:30 【问题描述】:

我正在构建基于 Spring MVC 和 Spring Security 的基于 Web 的应用程序。

我已经实现了重置密码功能。系统管理员将重置任何用户的密码。随机生成的密码将通过电子邮件发送给用户,并将在数据库中更新。

现在我想每当用户使用随机生成的密码登录时,我想强制用户更改其密码。

请查看我的用户表。

userid bigint(20) 用户名 varchar(20) 密码 varchar(65) 电子邮件 varchar(50) 名字 varchar(20) 姓氏 varchar(20) 组名 varchar(50) 启用 tinyint(1) credentialsNonExpired tinyint(1)

我的身份验证提供商

    <!--
        Configuring Authentication Provider to make use of spring security
        provided Jdbc user management service
    -->
    <authentication-provider user-service-ref="jdbcUserService">
        <!--
            Configuring SHA-1 Password Encoding scheme to secure user credential
        -->
        <password-encoder ref="sha1PasswordEncoder" />
    </authentication-provider>
</authentication-manager>

我使用 JDBCUserDetailsS​​erviceJDBCDaoImpl 扩展为 jdbcUserService

我想在重置密码时将 credentialNonExpired 设置为我的用户表的 false 列。

我能做到。

但是当我登录时,spring security JDBCuserdetailsservice loadUserbyUsername 只获取用户名、密码、启用的列和其余所有字段设置为 true。

protected List<UserDetails> loadUsersByUsername(String username) 
    return getJdbcTemplate().query(usersByUsernameQuery, new String[] username, new RowMapper<UserDetails>() 
        public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException 
            String username = rs.getString(1);
            String password = rs.getString(2);
            boolean enabled = rs.getBoolean(3);
            return new User(username, password, enabled, true, true, true, AuthorityUtils.NO_AUTHORITIES);
        

    );

但我想要由重置密码设置的实际 credentialNonExpired 字段,以便 Spring Security 将抛出 CREDENTIALEXPIREDEXCEPTION。

我通过加载上述方法实现了这一点,但是当用户使用过期密码登录时,还有其他方法可以重定向用户以更改密码页面。

请告诉我该怎么做?

【问题讨论】:

【参考方案1】:

答案很晚,我不知道您使用的是 Spring 2 还是 Spring 3。 但在 Spring 3 中,您可以这样做。

在您的 Spring 安全上下文中包含以下内容:

<bean id="securityExceptionTranslationHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
    <property name="exceptionMappings">
        <props>
            <prop key="org.springframework.security.authentication.CredentialsExpiredException">/change_password_page</prop>
        </props>
    </property>
    <property name="defaultFailureUrl" value="/login_generic_error_page"/>
</bean>

当然,您可以将其他特定的身份验证例外映射到其他页面。

如果您使用 form-login 元素,则必须指定 authentication-failure-handler-ref 属性(如果使用,请删除 authentication-failure-url

<security:form-login ... authentication-failure-handler-ref="securityExceptionTranslationHandler">

最后一步是创建更改密码页面。

请记住,用户在重定向到更改密码页面时未经过身份验证。

【讨论】:

我正在解决一个非常相似的问题,并且也沿着这条路走下去……有没有关于如何最好地处理更改密码逻辑的建议?似乎试图复制所有正常的“登录”功能(检查密码、填写 SecurityContextHolder、返回错误代码)可能会变得很棘手...... 我正在使用 JPA 和模型,并且我正在直接更新这些,而无需经历整个 Spring 安全周期。在我看来,这是最快的方式。当然,在更改密码后,我会将用户重定向到登录页面。 是的,我认为你的方式会更快 :) 这就是我最终做的事情 - * UsernamePasswordResetAuthentication 使用用户名、密码和新密码 * 登录页面时使用新/确认密码字段适当的 * 登录过滤器,根据请求创建正确的身份验证对象 * 自定义 AuthenticationProvider(由于不同的原因已经存在),扩展为 1)使用现有密码进行身份验证,2)更新存储的密码,以及 3)使用新密码。 该自定义身份验证提供程序是重要的部分。但是,如果您因为其他原因已经拥有它...【参考方案2】:

您可以尝试继承 SimpleUrlAuthenticationSuccessHandler 并实现自定义逻辑来检查密码到期。对此SimpleUrlAuthenticationSuccessHandler 的引用可以传递给应用程序上下文中的form-login 元素。

【讨论】:

以上是关于强制用户在 Spring Security 中更改过期密码的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Security 中添加新用户

如何强制 Spring Security 更新 XSRF-TOKEN cookie?

Spring Security:添加“伪登录”以更改用户信息

您如何在 spring-security 中注销所有已登录的用户?

Spring Security:如何更改默认用户和密码?

登录时更改spring security中的用户名