Spring Security的登录表单默认使用它自己提供的页面,登录成功后也是默认的页面跳转,也可以自定义登录页面 mylogin.html:
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>第一个HTML页面title>
head>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
自定义表单验证:
<form name="f" action="/user/login" method="post">
<br/>
用户名:
<input type="text" name="username" placeholder="name"><br/>
密码:
<input type="password" name="password" placeholder="password"><br/>
<input name="submit" type="submit" value="提交">
form>
body>
html>
配置:
@Configuration
public class MyWebSecurityConfig3 extends WebSecurityConfigurerAdapter {
//指定不对密码进行加密父(spring security5.x开始,必须指定一种)
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root").password("123").roles("ADMIN", "DBA")
.and()
.withUser("admin").password("123").roles("ADMIN", "USER")
.and()
.withUser("sang").password("123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 定义当需要用户登录时候,转到的登录页面。
.loginPage("/mylogin.html") // 设置登录页面
.loginProcessingUrl("/user/login") // 自定义的登录接口
.and()
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**")
.access("hasAnyRole('ADMIN', 'USER')")
.antMatchers("/db/**")
.access("hasRole('ADMIN') and hasRole('DBA')")
.antMatchers("/mylogin.html").permitAll() // 设置所有人都可以访问登录页面
.anyRequest() // 任何请求,登录后可以访问
.authenticated()
.and()
.csrf().disable();
}
}
Controller:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "Hello";
}
@GetMapping("/admin/hello")
public String admin(){
return "hello admin!";
}
@GetMapping("/user/hello")
public String user(){
return "hello user!";
}
@GetMapping("/db/hello")
public String dba(){
return "hello dba!";
}
}
在前后端分离的开发方式中,前后端的数据交互通过JSON进行,这时,登录成功后就不是页面跳转了,而是一段JSON提示。
@Configuration
public class MyWebSecurityConfig4 extends WebSecurityConfigurerAdapter {
//指定不对密码进行加密父(必须指定一种)
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root").password("123").roles("ADMIN", "DBA")
.and()
.withUser("admin").password("123").roles("ADMIN", "USER")
.and()
.withUser("sang").password("123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 定义当需要用户登录时候,转到的登录页面。
.loginPage("/mylogin.html") // 设置登录页面
.loginProcessingUrl("/user/login") // 自定义的登录接口
.usernameParameter("name") //自定义用户名参数(默认为username)
.passwordParameter("passwd") //自定义密码参数(默认为password)
.successHandler(new AuthenticationSuccessHandler() {//登录成功处理逻辑
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
Object principal = authentication.getPrincipal();//获取当前登录用户的信息
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
httpServletResponse.setStatus(200);
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", principal);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {//登录失败处理逻辑
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
httpServletResponse.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 om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**")
.access("hasAnyRole('ADMIN', 'USER')")
.antMatchers("/db/**")
.access("hasRole('ADMIN') and hasRole('DBA')")
.antMatchers("/mylogin.html").permitAll() // 设置所有人都可以访问登录页面
.anyRequest() // 任何请求,登录后可以访问
.authenticated()
.and()
.csrf().disable();
}
}
修改配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 定义当需要用户登录时候,转到的登录页面。
.loginPage("/mylogin.html") // 设置登录页面
.loginProcessingUrl("/user/login") // 自定义的登录接口
.usernameParameter("name") //自定义用户名参数(默认为username)
.passwordParameter("passwd") //自定义密码参数(默认为password)
.successHandler(new AuthenticationSuccessHandler() {//登录成功处理逻辑
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
Object principal = authentication.getPrincipal();//获取当前登录用户的信息
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
httpServletResponse.setStatus(200);
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("msg", principal);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {//登录失败处理逻辑
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
httpServletResponse.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 om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
.logout()//开启注销登录的配置
.logoutUrl("/user/logout")//配置注销登录请求url为"/user/logout",默认为"/logout"
.clearAuthentication(true)//清除身份认证信息,默认为true
.invalidateHttpSession(true)//是否使session失效,默认为true
.addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
}
})//注销时的回调
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.sendRedirect("/mylogin.html");
}
})//注销成功时的回调
.and()
.authorizeRequests() // 定义哪些URL需要被保护、哪些不需要被保护
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**")
.access("hasAnyRole('ADMIN', 'USER')")
.antMatchers("/db/**")
.access("hasRole('ADMIN') and hasRole('DBA')")
.antMatchers("/mylogin.html").permitAll() // 设置所有人都可以访问登录页面
.anyRequest() // 任何请求,登录后可以访问
.authenticated()
.and()
.csrf().disable();
}