Custom User
Explanation
- User names and passwords are generally stored in a database, form input username and password and check out the database of user names and passwords for comparison
- The following examples SpringSecurity5.x
Achieve UserDetailsService Interface
@Service
public class UserService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//此处根据用户名在数据库中查找,这里不再查找,直接返回一个org.springframework.security.core.userdetails.User对象(如果是自定义的User类,需要实现UserDetails接口)
return new User(username,new BCryptPasswordEncoder().encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
- AuthorityUtils.commaSeparatedStringToAuthorityList () method for simulating a privilege of admin, the method may be converted to a comma delimited string permission set (understood)
- User authentication process
to find the user information from the database, if it is empty, an exception is thrown, otherwise it returns a user object, again provided by the system DaoAuthenticationProvider class to compare the password is correct - If you write your own User entity class needs to implement UserDetails Interface
Write configuration class
@Configuration
public class BrowserSecurity extends WebSecurityConfigurerAdapter {
//引入自定义UserDetailsService
@Autowired
private UserService userService;
//加密
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置内存认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
}
UserDetails Interface Overview
User custom class that implements the interface, which method has the following main
- getAuthorities () : Get the current user role information object
- getPassword () : Gets the password for comparison with the password entered by the user
- getUsername : Get the current user name of the user object
- isAccountNonExpired () : whether the current user is not expired, custom logic may determine if the returns false, throws AccountExpiredException
- isAccountNonLocked () : whether the current user is not locked, the custom logic Analyzing
- isCredentialsNonExpired () : the current account password is not expired
- isEnabled () : The current account is available
Custom login page
Explanation
- In the login form is generally used in their login page
- We need to configure the settings in SpringSecurity
A simple login page
- In the resources / static write a login page directory
myLogin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>自定义登录页面登录</title>
</head>
<body>
<form action="/login" method="post">
<div class="form">
<h3>账户登录</h3>
<input type="text" placeholder="用户名" name="username" required="required" /></br>
<input type="password" placeholder="密码" name="password" required="required" />
<button type="submit">登录</button>
</div>
</form>
</body>
</html>
Increase the allocation on the basis of the custom user
Overall configuration is as follows:
@Configuration
public class BrowserSecurity extends WebSecurityConfigurerAdapter {
//引入自定义UserDetailsService
@Autowired
private UserService userService;
//加密
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置内存认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
//配置HttpSecurity
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//授权配置
.antMatchers("/myLogin.html").permitAll().anyRequest().authenticated()
.and()
//表单配置
.formLogin().loginPage("/myLogin.html").loginProcessingUrl("/login")
.and()
//默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
.csrf().disable();
}
}
result
In addition to the login page can be accessed directly, other requests need to jump to login page after the completion of certification can be accessed
Custom logon success and failure
Modify the form login configuration
Overall configuration is as follows:
@Configuration
public class BrowserSecurity extends WebSecurityConfigurerAdapter {
//引入自定义UserDetailsService
@Autowired
private UserService userService;
//加密
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
//配置内存认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置UserDetailsService以及密码规则
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
//配置HttpSecurity
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//授权配置
.antMatchers("/myLogin.html").permitAll().anyRequest().authenticated()
.and()
//表单配置
.formLogin().loginPage("/myLogin.html").loginProcessingUrl("/login")
.successHandler(new AuthenticationSuccessHandler() {
//登录成功返回一段json信息
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//Authentication authentication 包含用户登录信息
String name = authentication.getName();
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(200);
Map<String,Object> map = new HashMap<>();
map.put("status",200);
map.put("msg",name);
ObjectMapper mapper = new ObjectMapper();
out.write(mapper.writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
//登录失败,根据相关异常返回失败信息
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
response.setStatus(401);
Map<String,Object> map = new HashMap<>();
map.put("status",401);
if(e instanceof LockedException){
map.put("msg","账户被锁定");
}else if(e instanceof BadCredentialsException){
map.put("msg","账户名或密码错误");
}else if(e instanceof DisabledException){
map.put("msg","账户被禁用");
}else if(e instanceof AccountExpiredException){
map.put("msg","账户已过期");
}else if(e instanceof CredentialsExpiredException){
map.put("msg","密码已过期");
}else{
map.put("msg","登录失败");
}
ObjectMapper mapper = new ObjectMapper();
out.write(mapper.writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
//默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
.csrf().disable();
}
}
Class can also be implemented as a custom interface
- Successful login: Implement org.springframework.security.web.authentication.AuthenticationSuccessHandler interface onAuthenticationSuccess method
@Component
public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(mapper.writeValueAsString(authentication));
}
}
- Login failed: to achieve
org.springframework.security.web.authentication.AuthenticationFailureHandler of onAuthenticationFailure method
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException {
}
}
- After introduction in the configuration class
@Autowired
private MyAuthenticationSucessHandler authenticationSucessHandler;
@Autowired
private MyAuthenticationFailureHandler authenticationFailureHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.successHandler(authenticationSucessHandler) // 处理登录成功
.failureHandler(authenticationFailureHandler) // 处理登录失败
}
result
login successful
Login failed