Spring Security专栏(Security中的加密技术)

824 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

写在前面

通过前几篇的学习。我们大概了解了 Security的用户认证体系,这是基础。

用户认证的过程通常涉及密码的校验,因此密码的安全性也是我们需要考虑的一个核心问题。Spring Security 作为一款功能完备的安全性框架,一方面提供了用于完成认证操作的 PasswordEncoder 组件,另一方面也包含一个独立而完整的加密模块

多说一句,欢迎大家点击我头像,去查看我的专栏,我们一起学习!!!,设计模式专题已经完结,接下来主要完成Security专栏和并发队列专栏。

PasswordEncoder

在上篇文章中我们也介绍了基于数据库的用户信息存储方案,我们看下方代码:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 
        auth.jdbcAuthentication().dataSource(dataSource)
               .usersByUsernameQuery("select username, password, enabled from Users " + "where username=?")
               .authoritiesByUsernameQuery("select username, authority from UserAuthorities " + "where username=?")
               .passwordEncoder(new BCryptPasswordEncoder());
}

请注意,在上述方法中,我们通过 jdbcAuthentication() 方法验证用户信息时一定要集成加密机制,也就是使用 passwordEncoder() 方法嵌入一个 PasswordEncoder 接口的实现类。

PasswordEncoder 接口

在 Spring Security 中,PasswordEncoder 接口代表的是一种密码编码器,其核心作用在于指定密码的具体加密方式,以及如何将一段给定的加密字符串与明文之间完成匹配校验。PasswordEncoder 接口定义如下:

public interface PasswordEncoder {
    //对原始密码进行编码
    String encode(CharSequence rawPassword);
    //对提交的原始密码与库中存储的加密密码进行比对
    boolean matches(CharSequence rawPassword, String encodedPassword);
    //判断加密密码是否需要再次进行加密,默认返回 false
    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

Spring Security 内置了一大批 PasswordEncoder 接口的实现类,如下所示:

image.png

我们对上图中比较常见的几个 PasswordEncoder 接口展开叙述。

  • NoOpPasswordEncoder:以明文形式保留密码,不对密码进行编码。这种 PasswordEncoder 通常只用于演示,不应该用于生产环境。

  • StandardPasswordEncoder:使用 SHA-256 算法对密码执行哈希操作。

  • BCryptPasswordEncoder:使用 bcrypt 强哈希算法对密码执行哈希操作。

  • Pbkdf2PasswordEncoder:使用 PBKDF2 算法对密码执行哈希操作。

下面我们以 BCryptPasswordEncoder 为例,看一下它的 encode 方法,如下所示:

public String encode(CharSequence rawPassword) {
        String salt;
        if (random != null) {
           salt = BCrypt.gensalt(version.getVersion(), strength, random);
        } else {
           salt = BCrypt.gensalt(version.getVersion(), strength);
        }
        return BCrypt.hashpw(rawPassword.toString(), salt);
}

可以看到,上述 encode 方法执行了两个步骤,首先使用 Spring Security 提供的 BCrypt 工具类生成盐(Salt),然后根据盐和明文密码生成最终的密文密码。这里有必要对加盐的概念做一些展开:所谓加盐,就是在初始化明文数据时,由系统自动往这个明文里添加一些附加数据,然后散列。引入加盐机制是为了进一步保证加密数据的安全性,单向散列加密以及加盐思想也被广泛应用于系统登录过程中的密码生成和校验。

同样,在 Pbkdf2PasswordEncoder 中,也是通过对密码加盐之后进行哈希,然后将结果作为盐再与密码进行哈希,多次重复此过程,生成最终的密文。

介绍完 PasswordEncoder 的基本结构,我们继续来看它的应用方式。如果我们想在应用程序中使用某一个 PasswordEncoder 实现类,通常只需要通过它的构造函数创建一个实例,例如:

PasswordEncoder p = new StandardPasswordEncoder(); 
PasswordEncoder p = new StandardPasswordEncoder("secret");
 
PasswordEncoder p = new SCryptPasswordEncoder(); 
PasswordEncoder p = new SCryptPasswordEncoder(16384, 8, 1, 32, 64);

而如果想要使用 NoOpPasswordEncoder,除了构造函数之外,还可以通过它的 getInstance() 方法来获取静态实例,如下所示:

PasswordEncoder p = NoOpPasswordEncoder.getInstance()

总结

好了 今天就学到这里,今天之所以讲这个加密技术,主要有以下原因:

对于一个 Web 应用程序而言,一旦需要实现用户认证,势必涉及用户密码等敏感信息的加密。为此,Spring Security 专门提供了 PasswordEncoder 组件对密码进行加解密。Spring Security 内置了一批即插即用的 PasswordEncoder,并通过代理机制完成了各个组件的版本兼容和统一管理。这种设计思想也值得我们学习和借鉴。

下期我们学习下 如何自定义加密。 下期见

感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。也欢迎有问题我们下面评论交流

加油! 我们下期再见!

给大家分享几个我前面写的几篇骚操作

聊聊不一样的策略模式(值得收藏)

copy对象,这个操作有点骚!