Spring Security(二)

Spring Security(二)

注:凡是源码部分,我已经把英文注释去掉了,有兴趣的同学可以在自己项目里进去看看。😃

定义用户认证逻辑

用户登录成功后,用户的信息会被 Security 封装在一个接口里(“UserDetailsService”)

UserDetailsService 源码:

public interface UserDetailsService {
   // UserDetails 封装的用户信息接口
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

处理密码加密解密

Spring Security 处理登录密码的是 PasswordEncoder 接口。

PasswordEncoder 源码:

public interface PasswordEncoder {
    
    // 用来把用户登录时传入的密码进行加密处理
	String encode(CharSequence rawPassword);
    
    // 用来判断加密后的密码和用户传入的代码是否匹配
	boolean matches(CharSequence rawPassword, String encodedPassword);

}

Security 为 PasswordEncoder 接口提供了默认的实现 BCryptPasswordEncoder ,在项目中配置上密码加解密如下:

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        // Security 默认实现
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 启用表单登陆
        http.formLogin()
            .and()
            // 对请求做授权
            .authorizeRequests()
            // 任何请求
            .anyRequest()
            // 都需要身份认证
            .authenticated();
    }
}

配置 UserDetailService 接口实现:

@Configuration
public class MyUserDetailsService implements UserDetailsService {

    private static final Logger log = LoggerFactory.getLogger(MyUserDetailsService.class);

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("登录用户名 ={}", username);
        // 根据用户名查询用户信息(此处省略与数据库交互逻辑)
        // 下面的“User”对象是Security的,它实现了UserDetailsService接口
        List<GrantedAuthority> grantedAuthorities =
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        // 根据查找到的用户信息判断用户是否被冻结
        String encode = passwordEncoder.encode("123456");
        log.info("加密后的密码 ={}", encode);
        return new User(username, encode,
                true, true, true, true, grantedAuthorities);
    }

}

登录后,日志如下:

2019-01-10 01:22:10.946  INFO 6572 --- [nio-8081-exec-3] c.i.s.browser.MyUserDetailsService       : 登录用户名 =root
2019-01-10 01:22:11.074  INFO 6572 --- [nio-8081-exec-3] c.i.s.browser.MyUserDetailsService       : 加密后的密码 =$2a$10$8NCzA8f.T9vLijKnrI9BKOKVB53FB4esFG1QlaBT1Fmh2I5ITjRGm

由此可见,Security 默认的加解密接口实现中的密码加密并不是我们所熟悉的 MD5 ,如果想使用 MD5 加密,可自定义一个 PasswordEncoder 接口的实现类,如下:

/**
 * 自定义 PasswordEncoder 接口实现
 */
public class MyPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        String pwd = rawPassword.toString();
        return DigestUtil.md5Hex(pwd);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return this.encode(rawPassword).equalsIgnoreCase(encodedPassword);
    }
}
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        // Security 自定义实现
        return new MyPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 启用表单登陆
        http.formLogin()
            .and()
            // 对请求做授权
            .authorizeRequests()
            // 任何请求
            .anyRequest()
            // 都需要身份认证
            .authenticated();
    }
}
posted @ 2019-01-11 16:10  achnly  阅读(299)  评论(0编辑  收藏  举报