Spring|SpringSecurity--自定义登录页面、注销登录配置

自定义页面
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"
Spring|SpringSecurity--自定义登录页面、注销登录配置
文章图片

登录成功返回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(); } }

测试:登录成功,返回用户的基本信息,密码已经过滤掉了。
Spring|SpringSecurity--自定义登录页面、注销登录配置
文章图片

登录失败,返回失败信息:
Spring|SpringSecurity--自定义登录页面、注销登录配置
文章图片

注销登录配置
修改配置:
@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的默认实现:
Spring|SpringSecurity--自定义登录页面、注销登录配置
文章图片

    推荐阅读