摘要认证的密码加密

在之前的案例中,我们的密码都是以明文形式存储在数据库中,明文存储给系统安全带来了极大的风险。本节将演示在摘要认证中,实现对密码进行加密存储。

digest-authentication项目的基础上,我们构建了一个digest-password-encode项目。

build.gradle

修改 build.gradle 文件,让我们的digest-password-encode项目成为一个新的项目。

修改内容也比较简单,修改项目名称及版本即可。

  1. jar {
  2. baseName = 'digest-password-encode'
  3. version = '1.0.0'
  4. }

密码加密算法

Spring Security 所使用的密码加密算法格式为 HEX( MD5(username:realm:password) )所以,当我们使用账号 waylau 密码 123456 时,生成的密码如下:

  1. waylau:spring security tutorial:123456 -> b7ace5658b44f7295e7e8e36da421502

具体生成的密码的代码可以看 ApplicationTests.java:

  1. @Test
  2. public void testGenerateDigestEncodePassword() {
  3. String username = "waylau";
  4. String realm = "spring security tutorial";
  5. String password = "123456";
  6. String a1Md5 = this.encodePasswordInA1Format(username, realm, password);
  7. System.out.println("a1Md5:" + a1Md5);
  8. }
  9. private String encodePasswordInA1Format(String username, String realm, String password) {
  10. String a1 = username + ":" + realm + ":" + password;
  11. return md5Hex(a1);
  12. }
  13. private String md5Hex(String data) {
  14. MessageDigest digest;
  15. try {
  16. digest = MessageDigest.getInstance("MD5");
  17. }
  18. catch (NoSuchAlgorithmException e) {
  19. throw new IllegalStateException("No MD5 algorithm available!");
  20. }
  21. return new String(Hex.encode(digest.digest(data.getBytes())));
  22. }

这样,我们的数据库中可以存储加密后的密码,这样,就避免了明文存储的风险。

在初始化用户时,我们把加密后的密码存储进数据库:

  1. INSERT INTO user (id, username, password, name, age) VALUES (1, 'waylau', 'b7ace5658b44f7295e7e8e36da421502', '老卫', 30);
  2. INSERT INTO user (id, username, password, name, age) VALUES (2, 'admin', 'b7b20c789238e2a46e56b533c87e673c', 'Way Lau', 29);

如果启用密码加密机制

DigestAuthenticationFilter.passwordAlreadyEncoded 设置为 true 即可:

  1. @Bean
  2. public DigestAuthenticationFilter digestAuthenticationFilter(
  3. DigestAuthenticationEntryPoint digestAuthenticationEntryPoint) throws Exception {
  4. DigestAuthenticationFilter digestAuthenticationFilter = new DigestAuthenticationFilter();
  5. digestAuthenticationFilter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);
  6. digestAuthenticationFilter.setUserDetailsService(userDetailsService);
  7. digestAuthenticationFilter.setPasswordAlreadyEncoded(true); // 密码已经加密
  8. return digestAuthenticationFilter;
  9. }

限制

除默认的加密方式外,不能在摘要认证上采用其他的密码加密方式。