PasswordEncoder加密
SpringSecurity提供了Argon2、BCrypt等单向加密算法,安全性高,但开销大。因此针对高并发性能高的大型信息系统SpringSecurity推荐使用Oauth、Token等开销小的短期加密算法。
SpringSecurity规定必须设置一个默认的加密方式,不允许使用明文。
PasswordEncoder是SpringSecurity中处理密码加密和校验的接口,接口中常用2个方法:
- encode:对原始密码字符串进行加密。
- matches:校验输入密码字符串和加密后的字符串是否匹配。
其常用的实现类为org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder。
创建加密实现类
验证BCryptPasswordEncoder。
public static void main(String[] args) {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String pass1 = bCryptPasswordEncoder.encode("123");
String pass2 = bCryptPasswordEncoder.encode("123");
System.out.println(pass1);//$2a$10$c3JpJDFW692h2jY8l1uCruSMSiHDjPfvUZb0dMShXzpUEybZAgryS
System.out.println(pass2);//$2a$10$BAV3fgmEunsNY7xKJPtMlOcagR6.RQXwNho4caWrxJGQ5r5rEP3ci
boolean o1 = bCryptPasswordEncoder.matches("123", pass1);
boolean o2 = bCryptPasswordEncoder.matches("123", pass2);
System.out.println(o1);//true
System.out.println(o2);//true
}
可以发现,对同一个字符串的两次加密结果是不一样的,主要原因是加盐和哈希算法,加盐每次是随机的。
但是通过matches仍然可以匹配,所以加密时使用的盐值被写在了最终生成的加密字符串中。
静态用户和权限创建
一、在自定义权限配置类SecurityConfig中添加加密类。
二、复写configure(AuthenticationManagerBuilder auth),作用是创建静态用户并设定其角色或权限,设定其加密方式。
创建了用户a,拥有角色r1;用户b,拥有权限p1。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public PasswordEncoder p;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中构建静态的用户以及用户角色与权限
auth.inMemoryAuthentication()
//创建用户a,并设置其角色为r1,当然一个用户可以设定多个角色
.withUser("a").password(p.encode("123")).roles("r1")
.and()
//创建用户b,并设置其权限为p1,当然一个用户可以设定多个权限
.withUser("b").password(p.encode("456")).authorities("p1")
.and()
//设定加密方式
.passwordEncoder(p);
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//拦截并认证所有的请求
http.authorizeRequests()
//对于登录接口或登录页面不拦截
.antMatchers("/login","/mlogin.html").permitAll()
//对于接口访问必须需要某角色
.antMatchers("/role").hasRole("r1")
//对于接口访问必须需要某权限
.antMatchers("/perm").hasAuthority("p1")
//所有的请求必须经过认证(包括登录),除非加入上面的不拦截
.anyRequest().authenticated()
//再返回一个HttpSecurity http
.and()
//设置登录页面
.formLogin().loginPage("/mlogin.html")
//登录页面填写完成后的提交地址,默认是/login(SpringSecurity已经默认实现了此接口)
.loginProcessingUrl("/login")
//登录页面form表单中用户名框对应的name
.usernameParameter("username")
//登录页面form表单中密码框对应的name
.passwordParameter("password")
//登录成功后访问
.defaultSuccessUrl("/index")
//登录失败后访问
.failureForwardUrl("/loginerror");
//关闭跨域攻击
http.csrf().disable();
}
}
测试结果分析:
- 访问http://localhost:8080/index,输入用户名密码aaa/123456【已在配置文件中配置】,发现认证错误,因为在配置文件中未使用加密算法加密初始密码。
- 输入a/123,访问http://localhost:8080/role成功【用户a拥有角色r1】,访问http://localhost:8080/perm无权限。
- 输入b/456,访问http://localhost:8080/role无权限,访问http://localhost:8080/perm成功【用户b拥有角色p1】。