微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Spring Security中,UserDetails将密码存储为字符串,但我将其存储为字节[]

如何解决在Spring Security中,UserDetails将密码存储为字符串,但我将其存储为字节[]

我目前正在许多Springboot教程中类似地找到的UserDetailsS​​erviceImpl java类中编码loadUserByUsername方法。问题出在最后一行

return new org.springframework.security.core.userdetails.User(user.getEmail(),user.getpassword(),grantedAuthorities);

根据春季安全性文档,user.getpassword()应该返回一个字符串,但是我使用的是bcrypt和MysqL,因此,当我存储密码时,我将它以二进制(60)的形式存储在MysqL中,当我读取它时从数据库进入用户类,然后被读入

   @Entity
   @Data
   @AllArgsConstructor
   @NoArgsConstructor
   public class users {
    
    @Id
    private String email;
    private long phone_number;
    private String first_name;
    private String last_name;
    private byte[] password;
    private int gender;
        
}
我的用户类别中的

字段。如果我将其转换为字符串,我已经读到它弄乱了密码,但是如果我不这样做,则该函数将不起作用,因为我传递的是byte []而不是字符串。如何在保持此功能的同时保持bcrypt的安全性?

因为在MysqL文档中,它将BINARY(60)映射到byte []此处https://dev.mysql.com/doc/ndbapi/en/mccj-using-clusterj-mappings.html

每个人都说要在此处将bcrypt存储为二进制(60) What column type/length should I use for storing a Bcrypt hashed password in a Database?

解决方法

您可以仅将哈希密码作为字符串返回。无需返回普通密码。实际上,没有人会期望您。

这里的幕后有很多Spring魔术,并且有一个默认的密码编码器/解码器,例如您可以使用PasswordEncoderFactories.createDelegatingPasswordEncoder()获取密码编码器,该编码器还具有更多自定义选项。当用户登录时,将从UserDetails.getPassword()返回的散列密码与用户用于登录的密码的散列版本进行比较

我不太熟悉mysql数据类型,但是如果让Spring JPA管理用户实体,并且它具有一个密码字段,该字段使用此PasswordEncoderFactories.createDelegatingPasswordEncoder()进行编码,然后另存为String,数据库将只是varchar或在MySql中调用的任何类型。默认情况下,此密码编码器使用BCrypt,但您也可以将其配置为使用其他哈希算法。

,

根据第一个答案,您必须将数据库中的哈希密码与用户使用passwordEncoder.matches(passwordFromUser,encodedPassword)发送的密码进行比较。

您可以创建一个Bean来轻松漂亮地将passwordEncoder注入到UserDetailsService中。

,

将bcrypt存储为binary(60)大多是有争议的。根据我的经验,我会推荐varchar。由于您在保存之前创建了一个密码哈希,因此以后将其与用户提供的密码进行比较就不会成为问题(显然,您也必须对这个密码进行哈希处理)。

您说的是

如果我将其转换为字符串,我已经读到它弄乱了密码

我认为可以通过使用mysql it self的cast来避免这种情况。尽管它绕来绕去没有任何意义。

春季5引入了DelegatingPasswordEncoder。一个密码编码器,它基于前缀标识符委派给另一个PasswordEncoder。

例如,您可以:

class DefaultPasswordEncoderFactories {
  //the passwords must be of form: {bcrypt}xxx in the db
    static PasswordEncoder createDelegatingPasswordEncoder() {
        String encodingId = "bcrypt";
        Map<String,PasswordEncoder> encoders = new HashMap<>();
        encoders.put(encodingId,new BCryptPasswordEncoder());
        encoders.put("pbkdf2",new Pbkdf2PasswordEncoder());
        encoders.put("scrypt",new SCryptPasswordEncoder());

        DelegatingPasswordEncoder delegatingPasswordEncoder = new DelegatingPasswordEncoder(encodingId,encoders);
        delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder(12));
        return delegatingPasswordEncoder;
    }   
}

例如,可以在DaoAuthenticationProvider中轻松使用它:

private final PasswordEncoder passwordEncoder = DefaultPasswordEncoderFactories.createDelegatingPasswordEncoder();
...
@Bean
public DaoAuthenticationProvider authenticationProvider(){
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(ethUserDetailsService);
    provider.setPasswordEncoder(this.passwordEncoder);
    
    return provider;
}

检查以下链接,除了您提供的链接外,它可能很有用 What data type to use for hashed password field and what length?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。