自定义页面
Spring Security的登录表单默认使用它自己提供的页面,登录成功后也是默认的页面跳转,也可以自定义登录页面 mylogin.html:
第一个HTML页面
Title
自定义表单验证:
配置:
@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!";
}
}
【Spring|SpringSecurity--自定义登录页面、注销登录配置】启动项目:访问"/admin/hello"
文章图片
登录成功返回JSON
在前后端分离的开发方式中,前后端的数据交互通过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, 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, 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, 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, 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();
}
LogoutHandler的默认实现:
文章图片
推荐阅读
- =======j2ee|spring用注解实现注入的@resource,@autowired,@inject区别
- jar|springboot项目打成jar包和war包,并部署(快速打包部署)
- 数据库|效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)...
- java人生|35K 入职华为Java开发那天,我哭了(这 5 个月做的一切都值了)
- Java毕业设计项目实战篇|Java项目:在线嘿嘿网盘系统设计和实现(java+Springboot+ssm+mysql+maven)
- 微服务|微服务系列:服务发现与注册-----Eureka(面试突击!你想了解的Eureka都在这里.持续更新中......)
- java|ApplicationListener和SpringApplicationRunListener的联系
- 性能|性能工具之 Jmeter 通过 SpringBoot 工程启动
- 代码狂魔|Spring源码分析之IOC容器初始化流程