写点什么

SpringSecurity 中的密码加密

作者:周杰伦本人
  • 2022 年 7 月 12 日
  • 本文字数:1951 字

    阅读完需:约 6 分钟

SpringSecurity 中的密码加密

今天这篇文章给大家介绍一下 Spring Security 中的密码加密的相关源码:


SpringSecurity 中默认的加密方案是 DelegatingPasswordEncoder,它是一个代理类,主要用来代理不同的密码加密方案,它是由 PasswordEncoderFactories 的 createDelegatingPasswordEncoder 方法提供默认的 DelegatingPasswordEncoder 实例,可以看到默认加密方案是 bcrypt


public class PasswordEncoderFactories {    public static PasswordEncoder createDelegatingPasswordEncoder() {        String encodingId = "bcrypt";        Map<String, PasswordEncoder> encoders = new HashMap();        encoders.put(encodingId, new BCryptPasswordEncoder());        encoders.put("ldap", new LdapShaPasswordEncoder());        encoders.put("MD4", new Md4PasswordEncoder());        encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));        encoders.put("noop", NoOpPasswordEncoder.getInstance());        encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());        encoders.put("scrypt", new SCryptPasswordEncoder());        encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));        encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));        encoders.put("sha256", new StandardPasswordEncoder());        encoders.put("argon2", new Argon2PasswordEncoder());        return new DelegatingPasswordEncoder(encodingId, encoders);    }
private PasswordEncoderFactories() { }
复制代码


从源码中我们可以看出来,它还支持其他的加密方式例如我们常用的 MD5 加密,值得注意的是,我们在前几篇文章中定义用户名密码的时候使用了 noop 加密,通过源码可以看出来,设置调用的是 NoOpPasswordEncoder 的实例,从类名我们也能猜出来,这是一种不经过加密的方式,也就是存放的直接是明文,这在我们测试的时候可以实现,一般情况下是不使用的,因为有一定的风险存在。


DelegatingPasswordEncoder 实现了 PasswordEncoder 接口,


实现 encode 接口,加密完成后给加密后的字符串添加前缀,表示采用的哪种加密方案。


public String encode(CharSequence rawPassword) {    return "{" + this.idForEncode + "}" + this.passwordEncoderForEncode.encode(rawPassword);}
复制代码


这就就是进行加密了

密码匹配

实现密码匹配接口:


public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) {    if (rawPassword == null && prefixEncodedPassword == null) {        return true;    } else {        String id = this.extractId(prefixEncodedPassword);        PasswordEncoder delegate = (PasswordEncoder)this.idToPasswordEncoder.get(id);        if (delegate == null) {            return this.defaultPasswordEncoderForMatches.matches(rawPassword, prefixEncodedPassword);        } else {            String encodedPassword = this.extractEncodedPassword(prefixEncodedPassword);            return delegate.matches(rawPassword, encodedPassword);        }    }}private String extractId(String prefixEncodedPassword) {        if (prefixEncodedPassword == null) {            return null;        } else {            int start = prefixEncodedPassword.indexOf("{");            if (start != 0) {                return null;            } else {                int end = prefixEncodedPassword.indexOf("}", start);                return end < 0 ? null : prefixEncodedPassword.substring(start + 1, end);            }        }    }
复制代码


先调用 extractId 方法从加密字符串中提取具体的加密方案,就是{ }中的字符,拿到后从 idToPasswordEncoder 中匹配,为 null 采用默认的 defaultPasswordEncoderForMatches 的密码匹配器进行匹配。


开发者向 spring 容器中注册一个 PasswordEncoder 实例,AuthenticationManager 使用该实例,没有提供就使用 DelegatingPasswordEncoder 的实例。

总结

好了 这就是 Spring Security 的密码加密相关的源码了,它的默认加密方式是 BCryptPasswordEncoder,我们生产中一般使用 MD5 加密,Spring Security 也是支持这种方式,只要我们在构造的时候传入 MD5 就可以


@Beanpublic MessageDigestPasswordEncoder messageDigestPasswordEncoder(){        return new MessageDigestPasswordEncoder("MD5");}
复制代码


这篇文章先到这里,对应密码加密和密码匹配的逻辑比较简单,下篇文章我们将讲解 Spring Security 的其他知识点,欢迎订阅我的博客。

发布于: 刚刚阅读数: 4
用户头像

还未添加个人签名 2020.02.29 加入

公众号《盼盼小课堂》,多平台优质博主

评论

发布
暂无评论
SpringSecurity中的密码加密_7月月更_周杰伦本人_InfoQ写作社区