前言
截止到现在,一一哥已经带各位学习了很多关于SpringSecurity的知识点,但是Spring Security作为一个安全框架,其中必然就应该带有安全加密方面的内容,所以本篇文章,一一哥 就带各位来学习Spring Security中的密码加密机制。
Let's go!
一. 密码加密简介
1. 散列加密概述
我们开发时进行密码加密,可用的加密手段有很多,比如对称加密、非对称加密、信息摘要等。在一般的项目里,常用的就是信息摘要算法,也可以被称为散列加密函数,或者称为散列算法、哈希函数。
这是一种可以从任何数据中创建数字“指纹”的方法,常用的散列函数有 MD5 消息摘要算法、安全散列算法(Secure Hash Algorithm)等。
大家可以加老师vx领取最新资料哦
2. 散列加密原理
散列函数通过把消息或数据压缩成摘要信息,使得数据量变小,将数据的格式固定下来,然后将数据打乱混合,再重新创建成一个散列值,从而达到加密的目的。
散列值通常用一个短的随机字母和数字组成的字符串来代表,一个好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理时,如果我们不抑制冲突来区别数据,会使得数据库中的记录很难找到。
但是仅仅使用散列函数还不够,如果我们只是单纯的使用散列函数而不做特殊处理,其实是有风险的!比如在两个用户密码明文相同时,生成的密文也会相同,这样就增加了密码泄漏的风险。
所以为了增加密码的安全性,一般在密码加密过程中还需要“加盐”,而所谓的“盐”可以是一个随机数,也可以是用户名。”加盐“之后,即使密码的明文相同,用户生成的密码密文也不相同,这就可以极大的提高密码的安全性。
传统的加盐方式需要在数据库中利用专门的字段来记录盐值,这个字段可以是用户名字段(因为用户名唯一),也可以是一个专门记录盐值的字段,但这样的配置比较繁琐。
3. Spring Security中的密码处理方案
那么在Spring Security中,对密码是怎么进行处理的呢?其实Spring Security对密码的处理方案,有如下3种方式:
-
对密码进行明文处理,即不采用任何加密方式;
-
采用MD5加密方式;
-
采用哈希算法加密方式。
4. BCryptPasswordEncoder简介
以上说的是3种密码处理方案,并不代表只有3种加密算法,这个请大家注意哦!
实际上,Spring Security提供了多种密码加密算法,但官方推荐使用的是BCrypt Password Encoder方案,如下图所示:
我们开发时,用户表中的密码通常是使用MD5等不可逆算法加密后存储,但为了防止彩虹表破解,可以先使用一个特定的字符串(如域名)进行加密,然后再使用一个随机的salt(盐值)加密。其中特定的字符串是程序代码中固定的,salt是每个密码单独随机的,我们一般会给用户表加一个字段单独存储,但这样比较麻烦。
而BCrypt算法却可以随机生成salt并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt。不同于 Shiro 中需要自己处理密码加盐,在 Spring Security 中,BCrypt Password Encoder 本身就自带了盐,所以处理起来非常方便。
另外BCryptPasswordEncoder使用BCrypt强哈希函数,我们在使用时可以选择提供strength和SecureRandom参数。strength值(取值在4~31之间,默认为10)越大,则密钥的迭代次数就越多,密钥迭代次数为2^strength。
二. 利用BCryptPasswordEncoder进行加密
了解了这些基本的理论知识之后,壹哥 就带各位进行代码实现啦。
我们继续在之前的案例基础之上进行本案例的代码实现,所以项目创建过程略过,请参考之前的章节内容。
1. 编写register接口
为了方便测试,我们首先在UserController中编写一个register接口,用于注册一个新用户,在添加用户时对密码进行加密。
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 添加用户.这里我们采用表单形式传参,传参形式如下:
* http://localhost:8080/user/register?username=test&password=123
*/
@GetMapping("/register")
public User registerUser(@RequestParam(required = false) User user){
user.setEnable(true);
user.setRoles("ROLE_ADMIN");
//对密码进行加密
user.setPassword(passwordEncoder.encode(user.getPassword()));
userMapper.addUser(user);
return user;
}
别忘了注入PasswordEncoder对象!
2. 配置密码加密算法
接下来我们在Security Config配置类中,配置到底该采用哪种密码加密算法。我们在Spring Boot环境中是非常容易实现加密算法配置的,只需要创建一个Password Encoder对象即可。
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
//放行register接口
.antMatchers("/user/register")
.permitAll()
.antMatchers("/user/**")
.hasRole("USER")
.antMatchers("/app/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll()
.and()
//对跨域请求伪造进行防护---->csrf:利用用户带有登录状态的cookie进行攻击的手段
.csrf()
.disable();
}
//配置采用哪种密码加密算法
@Bean
public PasswordEncoder passwordEncoder() {
//不使用密码加密
//return NoOpPasswordEncoder.getInstance();
//使用默认的BCryptPasswordEncoder加密方案
return new BCryptPasswordEncoder();
//strength=10,即密钥的迭代次数(strength取值在4~31之间,默认为10)
//return new BCryptPasswordEncoder(10);
//利用工厂类PasswordEncoderFactories实现,工厂类内