PassWordEncoder密码解析详解
BCryptPasswordEncoder类的用法
简介:BCryptPasswordEncoder是Spring Security官方推荐的密码解析器,平时多使用这个解析器
BCryptPasswordEncoder是对bcrypt强散列方法的具体实现,是基于Hash算法实现的单向加密,可以通过setength控制加密强度,默认为10
BCryptPasswordEncoder pw = new BCryptPasswordEncoder();
//加密
String encode = pw.encode("123");
System.out.println(encode); // $2a$10$iyQ1sb.sS/vxLrPo9byZSOKoy4VFLMAOmPZBvWhIps2kHGXO/wI8O
//比较密码
boolean matches = pw.matches("123", encode);
System.out.println(matches); //true
2.5 自定义登录逻辑
当进行自定义登录逻辑时需要用到之前讲解的UserDetailsService 和 PasswordEncoder 但是 Spring Security要求:当进行自定义登录逻辑时容器内必须有PasswordEncoder实例。所以不能直接new对象
2.5.1 编写配置类
@Configuration
public class SecuriytConfig {
// 把BCryptPasswordEncoder放给了spring容器去管理
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
2.5.2 编写service
//实现 UserDeatailsService接口 重写 loadUserByUsername方法 在里面写逻辑
@Service
public class UserDetailServiceImpl implements UserDetailsService
{
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//1.根据用户名去数据库查询,如果不存在抛UsernameNotFoundException异常
if(!"admin".equals(username)){
throw new UsernameNotFoundException("用户不存在");
}
//2.比较密码(注册时已经加密过)如果匹配成功返回UserDetails
String password = passwordEncoder.encode("123");
return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
}
}
2.6 自定义登录界面
虽然 Spring Security给我们提供了登录页面,但是对于实际项目中,大多喜欢使用自己的登录页面,所以Spring Security 中不仅仅提供了登录页面,还支持用户自定义登录页面。实现过程也比较简单,只需要修改配置类即可。
2.6.1 编写登录页面
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username" /> <br />
密码:<input type="password" name="password" /> <br/>
<input type="submit" value="登录" />
</form>
</body>
</html>
2.6.2 编写配置类
@Configuration
public class SecuriytConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable();
//表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//必须和表单提交的接口一样,会去执行自定义登录逻辑
.loginProcessingUrl("/login")
//登录成功后跳转的页面,post请求
.successForwardUrl("/toMain")
.failureForwardUrl("/toError");
//授权
http.authorizeRequests()
//放行 login.html /error.html不需要认证
.antMatchers("/login.html").permitAll()
.antMatchers("/error.html").permitAll()
//所有请求都必须认证才能访问,必须登录
.anyRequest().authenticated();
}
2.6.3 自定义设置请求账户和密码的参数
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username123" /> <br />
密码:<input type="password" name="password123" /> <br/>
<input type="submit" value="登录" />
</form>
</body>
</html>
@Configuration
public class SecuriytConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable();
//表单提交
http.formLogin()
//自定义入参
.usernameParameter("username123")
.passwordParameter("password123")
//自定义登录页面
.loginPage("/login.html")
//必须和表单提交的接口一样,会去执行自定义登录逻辑
.loginProcessingUrl("/login")
//登录成功后跳转的页面,post请求
.successForwardUrl("/toMain")
.failureForwardUrl("/toError");
//授权
http.authorizeRequests()
//放行 login.html /error.html不需要认证
.antMatchers("/login.html").permitAll()
.antMatchers("/error.html").permitAll()
//所有请求都必须认证才能访问,必须登录
.anyRequest().authenticated();
}
2.6.4 自定义登录成功处理器
@Configuration
public class SecuriytConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable();
//表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//必须和表单提交的接口一样,会去执行自定义登录逻辑
.loginProcessingUrl("/login")
//登录成功后跳转的页面,post请求
//.successForwardUrl("/toMain")
//自定义登录成功处理器
.successHandler(new MyAuthenticationSuccessHandler("/main.html"))
.failureForwardUrl("/toError");
//授权
http.authorizeRequests()
//放行 login.html /error.html不需要认证
.antMatchers("/login.html").permitAll()
.antMatchers("/error.html").permitAll()
//所有请求都必须认证才能访问,必须登录
.anyRequest().authenticated();
}
// 把BCryptPasswordEncoder放给了spring容器去管理
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
自定义类 MyAuthenticationSuccessHandler
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private String url;
public MyAuthenticationSuccessHandler (String url){
this.url=url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
User user = (User) authentication.getPrincipal();
System.out.println(user.getUsername());
//出于安全的考虑输出null
System.out.println(user.getPassword());
System.out.println(user.getAuthorities());
httpServletResponse.sendRedirect(url);
}
}
输出结果:
2.6.5 自定义失败成功处理器
@Configuration
public class SecuriytConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable();
//表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//必须和表单提交的接口一样,会去执行自定义登录逻辑
.loginProcessingUrl("/login")
//登录成功后跳转的页面,post请求
//.successForwardUrl("/toMain")
//自定义登录成功处理器
.successHandler(new MyAuthenticationSuccessHandler("/main.html"))
//.failureForwardUrl("/toError");
//自定义失败处理器
.failureHandler(new MyAuthenticacationFailureHandler("/error.html"));
//授权
http.authorizeRequests()
//放行 login.html /error.html不需要认证
.antMatchers("/login.html").permitAll()
.antMatchers("/error.html").permitAll()
//所有请求都必须认证才能访问,必须登录
.anyRequest().authenticated();
}
// 把BCryptPasswordEncoder放给了spring容器去管理
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
自定义类 MyAuthenticationFailureHandler
public class MyAuthenticacationFailureHandler implements AuthenticationFailureHandler
{
private String url;
public MyAuthenticacationFailureHandler (String url){
this.url=url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect(url);
}
}