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

发布于 2024-12-08 09:53:08 字数 4349 浏览 0 评论 0 原文

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

任务:

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

其他信息:

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

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

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

现在我想我还需要

        <password-encoder hash="sha" />

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


编辑

我发现这篇文章是信息丰富但还不够:如果我在 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; }
}

security.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注入SaltSource以提取给定userName 来自数据库。

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

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


Edit2:

刚刚了解到我的方法是..遗留..:(所以我想我只会使用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 等的版本)。 3.1 所以我想,我会

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

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

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

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

Is there a tutorial out there or does anyone have pointers on how to do the following with Spring-Security?

Task:

I need to get the salt from my database for the authenticating username and use it to encrypt the provided password (from the login page) to compare it to the stored encrypted password (a.k.a. authenticate the user).

additional information:

I use a custom database structure. A UserDetails object is created via a custom UserDetailsService which in turn uses a custom DAOProvider to get the information from the database.

my security.xml file so far:

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

now I guess I'll need

        <password-encoder hash="sha" />

but what else? How do I tell spring security to use the databaseprovided salt in order to encode the password?


edit:

I found This SO post to be informatative but not sufficient: If I define a salt source in my xml to be used by the password encoder, like so:

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

I'll have to write a custom SaltSource to use my custom salt. But that's not to be found inside the UserDetails object. So...

Alternative 1:

Can I use a custom Implementation of UserDetails which might then have the salt property?

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

and

@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
}

custom User Class:

public class UserDetailsImpl extends User{

    // ...

    private String salt;

    public String getSalt() { return salt; }

    public void setSalt(String salt) { this.salt = salt; }
}

security.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"/>

Alternative 2:

Otherwise I'd have to inject my accountDAO into the SaltSource to extract the salt for a given userName from the database.

BUT: How does Spring Security call the SaltSource? Always with saltSource.getSalt(userDetails)?

Then I'd just have to make sure my SaltSource uses userDetails.accountName on my accountDAO to retrieve the salt.


Edit2:

Just learned that my approach is.. legacy.. :( So I guess I'll just use the StandardPasswordEncoder (which I still have to figure out how to use exactly).

BTW: I implemented the first option with a custom UserDetails class extending the User class and just adding a salt property which an then be passed to the SaltSource as a userPropertyToUse just like it has been proposed in the SO post mentioned in Edit 1...


EDIT 3:

Just got the StandardPasswordEncoder working, so I'll leave some pointers here:

Use the StandardPasswordEncoder for Authentication:

<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>

This requires the spring-security-crypto module in version 3.1.0.RC? as far as I know. Couldn't find any repository that has a 3.0. version (even though somewhere it had the versions listed that included 3.0.6 and so on). Also the documentations talks about spring security 3.1 so I figured, I'll just go with that.

When creating a user (for me only an admin can do that), I just use

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

and I'm done.

Spring security will randomly create a salt and add it to the password string before storing it in the database so no salt column is needed anymore.

One can however also provide a global salt as a constructor argument (new StandardPasswordEncoder("12345");), but I didn't know how to set up my security configuration to retrieve that value from a bean instead of supplying a static string with <constructor-arg name="secret" value "12345" />. But I don't know how much that is needed anyway.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拒绝两难 2024-12-15 09:53:08

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

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

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

Edit 3 中所描述的,其中我留下了一些关于如何使用 StandardPasswordEncoder 的指示对于自动化盐与密码一起存储。

I'll mark this as answered, as I solved my problem and no other comments or answers were given:

Edit 1 - Alternative 1 answers the original question

BUT I had to learn that customized password salting is a legacy approach that is not needed in Spring Security 3.1 any more, as I describe in

Edit 3 where I left some pointers on how to use the StandardPasswordEncoder for automated Salts that are stored with the password.

雪落纷纷 2024-12-15 09:53:08

无论如何,我写了这篇博文,详细介绍了您所描述的内容:
http://rtimothy.tumblr.com/post /26527448708/spring-3-1-security-and-salting-passwords

For what it's worth, I wrote this blog post detailing what you've described:
http://rtimothy.tumblr.com/post/26527448708/spring-3-1-security-and-salting-passwords

妄想挽回 2024-12-15 09:53:08

要从 bean 检索全局 salt,请使用 Spring 表达式语言或 SpEL。

<beans:bean id="encoder" 
        class="org.springframework.security.crypto.password.StandardPasswordEncoder">
    <constructor-arg value="#{someotherBean.somePropertyWithAGetterMethod"/>
</beans:bean>

To retrieve the global salt from a bean, use the Spring Expression Language or SpEL.

<beans:bean id="encoder" 
        class="org.springframework.security.crypto.password.StandardPasswordEncoder">
    <constructor-arg value="#{someotherBean.somePropertyWithAGetterMethod"/>
</beans:bean>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文