Skip to main content
 首页 » 编程设计

authentication之Spring Security 自定义身份验证和密码编码

2024年04月30日27lovecherry

是否有教程或者有人指导如何使用 Spring-Security 执行以下操作?

任务:

我需要从数据库中获取用于身份验证用户名的盐,并使用它来加密提供的密码(从登录页面),以将其与存储的加密密码进行比较(也称为对用户进行身份验证)。

其他信息:

我使用自定义数据库结构。 UserDetails 对象是通过自定义 UserDetailsService 创建的,该对象又使用自定义 DAOProvider 从数据库获取信息。

到目前为止我的 security.xml 文件:

<authentication-manager> 
    <authentication-provider user-service-ref="userDetailsService"> 
    </authentication-provider> 
</authentication-manager> 

现在我想我需要

        <password-encoder hash="sha" /> 

但是还有什么?我如何告诉 spring security 使用数据库提供的盐来对密码进行编码?

<小时 />

编辑:

我发现 This SO 帖子内容丰富,但还不够:如果我在 xml 中定义密码编码器使用的盐源,如下所示:

        <password-encoder ref="passwordEncoder">                 
            <salt-source ref="saltSource"/> 
        </password-encoder> 

我必须编写一个自定义 SaltSource 才能使用我的自定义盐。但在 UserDetails 对象中找不到它。所以...

替代方案 1:

我可以使用 UserDetails 的自定义实现吗?它可能具有 salt 属性?

<beans:bean id="saltSource" class="path.to.MySaltSource" 
    p:userPropertyToUse="salt"/> 

@Service("userDetailsService")  
public class UserDetailsServiceImpl implements UserDetailsService { 
    public UserDetails loadUserByUsername(String username) 
            throws UsernameNotFoundException, DataAccessException { 
 
        // ... 
        return buildUserFromAccount(account); 
    } 
 
    @Transactional(readOnly = true) 
 
    UserDetailsImpl buildUserFromAccount(Account account){ 
 
        // ... build User object that contains salt property 
} 

自定义用户类别:

public class UserDetailsImpl extends User{ 
 
    // ... 
 
    private String salt; 
 
    public String getSalt() { return salt; } 
 
    public void setSalt(String salt) { this.salt = salt; } 
} 

安全.xml:

<authentication-manager> 
    <authentication-provider user-service-ref="userDetailsService"> 
        <password-encoder hash="sha">                 
        <salt-source ref="saltSource"/> 
    </password-encoder> 
    </authentication-provider> 
</authentication-manager> 
 
<beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource" p:userPropertyToUse="salt"/> 


替代方案 2:

否则我必须将我的 accountDAO 注入(inject) SaltSource 才能从数据库中提取给定 userName 的盐。

但是:Spring Security 如何调用 SaltSource ?总是带有 saltSource.getSalt(userDetails)

然后我只需要确保我的 SaltSource 在我的 userDetails.accountName 上使用 accountDAO 来检索盐。

<小时 />

编辑2:

刚刚了解到我的方法是..遗留的..:(所以我想我只会使用StandardPasswordEncoder(我仍然需要弄清楚如何准确使用它)。

顺便说一句:我使用扩展 User 类的自定义 UserDetails 类实现了第一个选项,然后添加一个 salt 属性,然后将其作为 userPropertyToUse 传递给 SaltSource,就像编辑 1 中提到的 SO 帖子中提出的那样...

<小时 />

编辑3:

刚刚让 StandardPasswordEncoder 正常工作,所以我将在这里留下一些提示:

使用 StandardPasswordEncoder 进行身份验证:

<beans:bean id="encoder"  
    class="org.springframework.security.crypto.password.StandardPasswordEncoder"> 
</beans:bean> 
 
 
<authentication-manager> 
    <authentication-provider user-service-ref="userDetailsService"> 
        <password-encoder ref="encoder" />          
    </authentication-provider> 
</authentication-manager> 

这需要 3.1.0.RC 版本中的 spring-security-crypto 模块?据我所知。找不到任何具有 3.0 的存储库。版本(即使某处列出了包含 3.0.6 等的版本)。另外,文档还讨论了 Spring Security 3.1,所以我想,我就这么做吧。

创建用户时(对我来说只有管理员可以这样做),我只使用

        StandardPasswordEncoder encoder = new StandardPasswordEncoder(); 
        String result = encoder.encode(password); 

我就完成了。

Spring security 将随机创建一个盐并将其添加到密码字符串中,然后将其存储在数据库中,因此不再需要盐列

但是,也可以提供全局盐作为构造函数参数( new StandardPasswordEncoder("12345"); ),但我不知道如何设置安全配置以从 bean 检索该值,而不是提供带有 <constructor-arg name="secret" value "12345" /> 的静态字符串。但我不知道到底需要多少。

请您参考如下方法:

我会将其标记为已回答,因为我解决了我的问题并且没有给出其他评论或答案:

编辑 1 - 替代方案 1 回答原始问题

但是我必须了解到,自定义密码加盐是一种传统方法,Spring Security 3.1 中不再需要这种方法,正如我在

中所描述的那样

编辑 3,我在其中留下了一些关于如何使用 StandardPasswordEncoder 来实现与密码一起存储的自动 Salt 的提示。