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

12

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

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

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

请查看我的用户表。

用户ID bigint(20)
用户名 varchar(20)
密码 varchar(65)
电子邮件 varchar(50)
名字 varchar(20)
姓氏 varchar(20)
组名 varchar(50)
启用 tinyint(1)
凭据未过期 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>

我使用了继承自 JDBCDaoImplJDBCUserDetailsService 作为 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。

我通过加载上述方法来实现这一点,但是否有其他方法在用户使用过期密码登录时将其重定向到更改密码页面。

请告诉我如何做到这一点?

2个回答

15

回答有些晚了,我不知道您是否在使用Spring 2或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、返回错误代码)可能会变得棘手... - bimsapi
1
我正在使用JPA和模型,直接更新这些而不经过整个Spring安全周期。对我来说,这似乎是最快的方法。当然,在更改密码后,我将用户重定向到登录页面。 - Adrian Ber
1
是的,我认为你的方法可能更快 :) 这是我最终采取的做法 -
  • UsernamePasswordResetAuthentication 使用用户名、密码和新密码
  • 登录页面在适当时候显示新/确认密码字段
  • 登录过滤器根据请求创建正确的身份验证对象
  • 自定义 AuthenticationProvider(已经存在于不同的原因),扩展为 1)使用现有密码进行身份验证,2)更新存储的密码,以及 3)使用新密码重新进行身份验证。
- bimsapi
那个自定义认证提供程序是重头戏。但如果你已经因其他原因拥有它... - Adrian Ber

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接