Spring Security 使用MD5加盐加密和BCrypt加密密码

之前我们都是使用MD5 Md5PasswordEncoder 或者SHA ShaPasswordEncoder 的哈希算法进行密码加密,在spring security中依然使用只要指定使用自定义加密算法就行,现在推荐spring使用的BCrypt BCryptPasswordEncoder,一种基于随机生成salt的根据强大的哈希加密算法。  

一、MD5加密

  1. package com.liuyanzhao.chuyun.util;
  2. import java.security.MessageDigest;
  3. /**
  4.  * @author 言曌
  5.  * @date 2018/2/9 下午6:11
  6.  */
  7. public class MD5Util {
  8.     private static final String SALT = "liuyanzhao.com";
  9.     /**
  10.      * MD5加盐加密
  11.      *
  12.      * @param password
  13.      * @return
  14.      */
  15.     public static String encode(String password) {
  16.         password = password + SALT;
  17.         MessageDigest md5 = null;
  18.         try {
  19.             md5 = MessageDigest.getInstance("MD5");
  20.         } catch (Exception e) {
  21.             throw new RuntimeException(e);
  22.         }
  23.         char[] charArray = password.toCharArray();
  24.         byte[] byteArray = new byte[charArray.length];
  25.         for (int i = 0; i < charArray.length; i++)
  26.             byteArray[i] = (byte) charArray[i];
  27.         byte[] md5Bytes = md5.digest(byteArray);
  28.         StringBuffer hexValue = new StringBuffer();
  29.         for (int i = 0; i < md5Bytes.length; i++) {
  30.             int val = ((int) md5Bytes[i]) & 0xff;
  31.             if (val < 16) {
  32.                 hexValue.append("0");
  33.             }
  34.             hexValue.append(Integer.toHexString(val));
  35.         }
  36.         return hexValue.toString();
  37.     }
  38.     public static void main(String[] args) {
  39.         String hashPass = MD5Util.encode("123456");
  40.         System.out.println(MD5Util.encode("123456"));//08dc78d36d1512e5a81ef05b01a37860
  41.         System.out.println("08dc78d36d1512e5a81ef05b01a37860".equals(hashPass));//true
  42.     }
  43. }
所谓加盐加密,就是在原先密码上加点“盐”然后加密。因为虽然MD5加密是不可逆的,但是别人可以根据你的MD5密码不断比较发现你的原密码,比如你的密码设置得很简单是123456,加密后是 e10adc3949ba59abbe56e057f20f883e,一旦数据库泄露,密码丢失,不法分子很容易试探出来原密码。如果加上盐,只要别人不知道盐是什么,破解难度会提高很多。  

二、BCrypt加密

  1. package com.liuyanzhao.chuyun.util;
  2. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  3. /**
  4.  * @author 言曌
  5.  * @date 2018/2/22 下午8:39
  6.  */
  7. public class BCryptUtil {
  8.     /**
  9.      * 对密码进行加密
  10.      * @param password
  11.      * @return
  12.      */
  13.     public static String encode(String password) {
  14.         BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
  15.         String hashPass = bcryptPasswordEncoder.encode(password);
  16.         return hashPass;
  17.     }
  18.     /**
  19.      * 对原密码和已加密的密码进行匹配,判断是否相等
  20.      * @param password
  21.      * @param encodedPassword
  22.      * @return
  23.      */
  24.     public static boolean match(String password,String encodedPassword) {
  25.         BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
  26.         boolean result = bcryptPasswordEncoder.matches(password, encodedPassword);
  27.         return result;
  28.     }
  29.     public static void main(String[] args) {
  30.         String hashPass = encode("123456");
  31.         System.out.println(hashPass);
  32.         System.out.println(match("123456",hashPass));//true
  33.         System.out.println(match("123456","$2a$10$7wOQPHU2MfHt3X4wCFx5H.EZu.rlHMtY5HTFsqXiPd6BA5vNHJNf2"));//true
  34.         System.out.println(match("123456","$2a$10$nYQWXcY.eVUwI8kYGtMCVOD0hWE4AKjzFg0oo91qc/ECQg/DD/CpS"));//true
  35.         System.out.println(match("123456","$2a$10$9etIPtquQ3f..ACQkDHAVuBfjBoDXXWHHCOBl/RaJADxuXdSQB6I2"));//true
  36.     }
  37. }
使用 BCrypt 加密需要导入 Spring Security 的依赖。 我们发现每次运行都会得到不同的加密密码,但是这些加密后的密码都和 123456 相等。  

三、Spring Security 使用 MD5 加密

SecurityConfig
  1. package com.liuyanzhao.chuyun.config;
  2. import com.liuyanzhao.chuyun.service.CustomUserService;
  3. import com.liuyanzhao.chuyun.util.MD5Util;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
  6. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  7. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  8. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  9. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  10. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  11. import org.springframework.security.crypto.password.PasswordEncoder;
  12. /**
  13.  * 安全配置类
  14.  *
  15.  * @author 言曌
  16.  * @date 2018/1/23 上午11:37
  17.  */
  18. @EnableWebSecurity
  19. @EnableGlobalMethodSecurity(prePostEnabled = true// 启用方法安全设置
  20. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  21.     private static final String KEY = "liuyanzhao.com";
  22.     /**
  23.      * 自定义用户Service验证
  24.      * @return
  25.      */
  26.     @Bean
  27.     CustomUserService customUserService() {
  28.         return new CustomUserService();
  29.     }
  30.     /**
  31.      * 核心配置
  32.      * @param auth
  33.      * @throws Exception
  34.      */
  35.     @Override
  36.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  37.         DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
  38.         authenticationProvider.setUserDetailsService(customUserService());
  39.         //使用 MD5 加密
  40.         auth.userDetailsService(customUserService()).passwordEncoder(new PasswordEncoder(){
  41.             @Override
  42.             public String encode(CharSequence rawPassword) {
  43.                 return MD5Util.encode((String)rawPassword);
  44.             }
  45.             @Override
  46.             public boolean matches(CharSequence rawPassword, String encodedPassword) {
  47.                 return encodedPassword.equals(MD5Util.encode((String)rawPassword));
  48.             }}); //user Details Service验证
  49.         auth.authenticationProvider(authenticationProvider);
  50.     }
  51.     /**
  52.      * 权限访问自定义配置
  53.      */
  54.     @Override
  55.     protected void configure(HttpSecurity http) throws Exception {
  56.         http.authorizeRequests()
  57.                 .antMatchers("/css/**""/js/**","/","/fonts/**","/users").permitAll() // 都可以访问
  58.                 .antMatchers("/h2-console/**").permitAll() // 都可以访问
  59.                 .antMatchers("/admin/**").hasRole("ADMIN"// 需要相应的角色才能访问
  60.                 .antMatchers("/console/**").hasAnyRole("ADMIN","USER"// 需要相应的角色才能访问
  61.                 .and()
  62.                 .formLogin()   //基于 Form 表单登录验证
  63.                 .loginPage("/login"//登录页面
  64.                 .failureUrl("/login?error=true"// 登录错误页面
  65.                 .and().logout()
  66.                 .and().rememberMe().key(KEY) // 启用 remember me
  67.                 .tokenValiditySeconds(1209600)//记住两周
  68.                 .and().exceptionHandling().accessDeniedPage("/403");  // 处理异常,拒绝访问就重定向到 403 页面
  69.         http.csrf().ignoringAntMatchers("/h2-console/**"); // 禁用 H2 控制台的 CSRF 防护
  70.         http.headers().frameOptions().sameOrigin(); // 允许来自同一来源的H2 控制台的请求
  71.     }
  72. }
这里的 MD5Util 可以直接用上面的第一步里的  

四、Spring Security 使用 BCrypt 加密

SecurityConfig
  1. package com.liuyanzhao.chuyun.config;
  2. import com.liuyanzhao.chuyun.service.CustomUserService;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
  5. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  6. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  7. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  9. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  10. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  11. import org.springframework.security.crypto.password.PasswordEncoder;
  12. /**
  13.  * 安全配置类
  14.  *
  15.  * @author 言曌
  16.  * @date 2018/1/23 上午11:37
  17.  */
  18. @EnableWebSecurity
  19. @EnableGlobalMethodSecurity(prePostEnabled = true// 启用方法安全设置
  20. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  21.     private static final String KEY = "liuyanzhao.com";
  22.     /**
  23.      * 自定义用户Service验证
  24.      * @return
  25.      */
  26.     @Bean
  27.     CustomUserService customUserService() {
  28.         return new CustomUserService();
  29.     }
  30.     /**
  31.      * 使用使用 BCrypt加密
  32.      * @return
  33.      */
  34.     @Bean
  35.     public PasswordEncoder passwordEncoder() {
  36.         return new BCryptPasswordEncoder();   // 使用 BCrypt 加密
  37.     }
  38.     /**
  39.      * 核心配置
  40.      * @param auth
  41.      * @throws Exception
  42.      */
  43.     @Override
  44.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  45.         DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
  46.         authenticationProvider.setUserDetailsService(customUserService());
  47.         authenticationProvider.setPasswordEncoder(passwordEncoder());
  48.         auth.authenticationProvider(authenticationProvider);
  49.     }
  50.     /**
  51.      * 权限访问自定义配置
  52.      */
  53.     @Override
  54.     protected void configure(HttpSecurity http) throws Exception {
  55.         http.authorizeRequests()
  56.                 .antMatchers("/css/**""/js/**","/","/fonts/**","/users").permitAll() // 都可以访问
  57.                 .antMatchers("/h2-console/**").permitAll() // 都可以访问
  58.                 .antMatchers("/admin/**").hasRole("ADMIN"// 需要相应的角色才能访问
  59.                 .antMatchers("/console/**").hasAnyRole("ADMIN","USER"// 需要相应的角色才能访问
  60.                 .and()
  61.                 .formLogin()   //基于 Form 表单登录验证
  62.                 .loginPage("/login"//登录页面
  63.                 .failureUrl("/login?error=true"// 登录错误页面
  64.                 .and().logout()
  65.                 .and().rememberMe().key(KEY) // 启用 remember me
  66.                 .tokenValiditySeconds(1209600)//记住两周
  67.                 .and().exceptionHandling().accessDeniedPage("/403");  // 处理异常,拒绝访问就重定向到 403 页面
  68.         http.csrf().ignoringAntMatchers("/h2-console/**"); // 禁用 H2 控制台的 CSRF 防护
  69.         http.headers().frameOptions().sameOrigin(); // 允许来自同一来源的H2 控制台的请求
  70.     }
  71. }
    最后,还是建议使用 BCrypt 加密,更安全,但是密码字段长度至少要60位。   本文地址:https://liuyanzhao.com/7569.html

发表评论

目前评论:8

  • avatar fsadfasd

    dfgdfsgdsfgsdfg

  • avatar 232

  • avatar 232

    在测试

  • avatar 232

    测试层级评论

  • avatar 232

    12131323

    • avatar 232

      @232sasasasasasa

      • avatar 232

        @232sasasasas

    • avatar 232

      @232大撒大撒