codec工具包

commons-codec 是一个 Apache 上的开源项目,用它可以方便的实现密码加密

引入依赖

  1. <dependency>
  2. <groupId>commons-codec</groupId>
  3. <artifactId>commons-codec</artifactId>
  4. <version>1.11</version>
  5. </dependency>

自定义加密类

@Component
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes()));
    }
}

在 Spring Security 中,PasswordEncoder 专门用来处理密码的加密与比对工作,我们自定义 MyPasswordEncoder 并实现 PasswordEncoder 接口,还需要实现该接口中的两个方法:

  1. encode 方法表示对密码进行加密,参数 rawPassword 就是你传入的明文密码,返回的则是加密之后的密文,这里的加密方案采用了 MD5。
  2. matches 方法表示对密码进行比对,参数 rawPassword 相当于是用户登录时传入的密码,encodedPassword 则相当于是加密后的密码(从数据库中查询而来)。

最后记得将 MyPasswordEncoder 通过 @Component 注解标记为 Spring 容器中的一个组件。

使用了 MyPasswordEncoder 之后,在用户注册时,就需要将密码加密之后存入数据库中,方式如下

public int reg(User user) {
    ...
    //插入用户,插入之前先对密码进行加密
    user.setPassword(passwordEncoder.encode(user.getPassword()));
    result = userMapper.reg(user);
    ...
}

BCryptPasswordEncoder 加密

但是自己定义 PasswordEncoder 还是有些麻烦,特别是处理密码加盐问题的时候。
所以在 Spring Security 中提供了 BCryptPasswordEncoder,
使得密码加密加盐变得非常容易。
只需要提供 BCryptPasswordEncoder 这个 Bean 的实例即可,

@Bean
PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(10);
}

创建 BCryptPasswordEncoder 时传入的参数 10 就是 strength,
即密钥的迭代次数(也可以不配置,默认为 10)
如下:
内存中的配置的用户的密码也不再是明文

auth.inMemoryAuthentication()
.withUser("admin")
.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
.roles("ADMIN", "USER")
.and()
.withUser("sang")
.password("$2a$10$eUHbAOMq4bpxTvOVz33LIehLe3fu6NwqC9tdOcxJXEhyZ4simqXTC")
.roles("USER");

本案例使用了配置在内存中的用户,
一般情况下,用户信息是存储在数据库中的,因此需要在用户注册时对密码进行加密处理,如下:

@Service
public class RegService {
    public int reg(String username, String password) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
        String encodePasswod = encoder.encode(password);
        return saveToDb(username, encodePasswod);
    }
}

用户将密码从前端传来之后,通过调用 BCryptPasswordEncoder 实例中的 encode 方法对密码进行加密处理,加密完成后将密文存入数据库。

源码

PasswordEncoder 是一个接口,里边只有三个方法:

public interface PasswordEncoder {
 String encode(CharSequence rawPassword);
 boolean matches(CharSequence rawPassword, String encodedPassword);
 default boolean upgradeEncoding(String encodedPassword) {
  return false;
 }
}
  • encode 方法用来对密码进行加密。
  • matches 方法用来对密码进行比对。
  • upgradeEncoding 表示是否需要对密码进行再次加密以使得密码更加安全,默认为 false。

PasswordEncoder 中的 encode 方法,是我们在用户注册的时候手动调用。
matches 方法,则是由系统调用,默认是在 DaoAuthenticationProvider#additionalAuthenticationChecks 方法中调用的。