加密案例
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encode = passwordEncoder.encode("123456");
System.out.println(encode); //$2a$10$svp.cYEelXIMGz/t952otuk2I7COcQLh.ZY3mC4TItFMtaC1Ij17m
sercurity自带的登录校验
重写security登录用户和密码
@Configuration
public class SecurityConfig {
//SpringBoot需要这个Bean,当需要加密时
@Bean
public PasswordEncoder getPw(){
return new BCryptPasswordEncoder();
}
}
配置
@Autowired
UserDetailServiceImpl mUserDetailsService;
@Autowired
PasswordEncoder mPasswordEncoder;
//认证配置
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(mUserDetailsService).passwordEncoder(mPasswordEncoder);
}
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
PasswordEncoder mPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查数据库,如果不存在就抛出UserNotFoundException
if(!"admin".equals(username)) throw new UsernameNotFoundException("用户名不存在");
//数据库中已经进行加密的密码
String dbpassword = mPasswordEncoder.encode("123456");
// 用户名 + 密码 + 授权权限
return new User(username,dbpassword, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
}
}
自定义登录界面配置
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form method="post" action="/user/login">
username: <input type="text" name="username"> <br/>
password: <input type="text" name="password"> <br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login") //跳转至登录页
.loginProcessingUrl("/user/login") //表单action提交接口,对接loadUserByUsername方法
.successForwardUrl("/index");
http.csrf().disable(); //关掉csrf才可以表单接口和UserDetailService方法对接
//认证拦截配置
http.authorizeRequests()
.antMatchers("/login").permitAll() //登录页放行
.anyRequest().authenticated(); //所有界面都需要认证
}
@Bean
public PasswordEncoder getPw(){
return new BCryptPasswordEncoder();
}
}
登录失败页
loginError.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录失败</title>
</head>
<body>
登录失败,请 <a href="/login">重新登录</a>
</body>
</html>
配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login") //跳转至登录页
.loginProcessingUrl("/user/login") //表单action提交接口,对接loadUserByUsername方法
.successForwardUrl("/index")
.failureForwardUrl("/loginError");
http.csrf().disable(); //关掉csrf才可以表单接口和UserDetailService方法对接
//认证
http.authorizeRequests()
.antMatchers("/login").permitAll() //登录页放行
.antMatchers("/loginError").permitAll() //登录失败页放行
.anyRequest().authenticated(); //所有界面都需要认证
}
认证界面和对接接口底层原理是
UsernamePasswordAuthenticationFilter
两个接口
当什么也没有配置的时候,账号和密码是由SpringSecurity生成的。而在实际项目中账号和密码都是从数据库中查询出来的。我已我们要通过自定义逻辑控制认证逻辑
UserDetailsService
自定义认证用户
自定义表单参数名
username: <input type="text" name="username123"> <br/>
password: <input type="text" name="password123"> <br/>
http.formLogin()
.usernameParameter("username123")
.passwordParameter("password123")
.loginPage("/login") //跳转至登录页
.loginProcessingUrl("/user/login") //表单action提交接口,对接loadUserByUsername方法
.successForwardUrl("/index")
.failureForwardUrl("/loginError");
http.csrf().disable(); //关掉csrf才可以表单接口和UserDetailService方法对接
登录成功|失败处理器
/**
* 项目名: learn_spring_security
* 包名: com.kcl.handler
* 文件名 My
* 创建者
* 创建时间: 2021/5/26 4:57 PM
* 描述 自定义登录成功处理器
*/
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 {
httpServletResponse.sendRedirect(url);
User user = (User) authentication.getPrincipal();
System.out.println(user.getUsername());
System.out.println(user.getPassword()); //null
System.out.println(user.getAuthorities());
}
}
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
private String url;
public MyAuthenticationFailureHandler(String url) {
this.url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.sendRedirect(url);
}
}
配置
antMatchers
功能 > 拦截器
** 文件下的所有资源
*当前文件夹下面的资源
.antMatchers("/css/**","/js/**", "/img/**").permitAll() //static目录下放行
其他
权限控制和角色控制
权限控制
用户认证分配权限
认证同时授权
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
PasswordEncoder mPasswordEncoder;
//自定义登录逻辑
//security自带登录界面 会 和该方法进行对接
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查数据库,如果不存在就抛出UserNotFoundException
if(!"admin".equals(username) && !"zhangsan".equals(username)) throw new UsernameNotFoundException("用户名不存在");
if("admin".equals(username)){
//数据库中已经进行加密的密码
String dbpassword = mPasswordEncoder.encode("123456");
// 用户名 + 密码 + 授权权限
return new User(username,dbpassword, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin"));
}
if("zhangsan".equals(username)){
//数据库中已经进行加密的密码
String dbpassword = mPasswordEncoder.encode("123456");
// 用户名 + 密码 + 授权权限
return new User(username,dbpassword, AuthorityUtils.commaSeparatedStringToAuthorityList("vip,ROLE_user"));
}
return null;
}
}
权限控制
//认证
http.authorizeRequests()
.antMatchers("/vip").hasAuthority("vip") //权限控制
.antMatchers("/admin").hasRole("admin") //角色控制
自定义403处理
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); //403
//返回json格式
httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员\"}");
writer.flush();
writer.close();
}
}
SecurityConfig中的configure方法中配置
//403权限不足,自定义处理
http.exceptionHandling()
.accessDeniedHandler(mMyAccessDeniedHandler);