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();
    }
}

测试结果分析:

  1. 访问http://localhost:8080/index,输入用户名密码aaa/123456【已在配置文件中配置】,发现认证错误,因为在配置文件中未使用加密算法加密初始密码。
  2. 输入a/123,访问http://localhost:8080/role成功【用户a拥有角色r1】,访问http://localhost:8080/perm无权限。
  3. 输入b/456,访问http://localhost:8080/role无权限,访问http://localhost:8080/perm成功【用户b拥有角色p1】。