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

自定义页面

Spring Security的登录表单默认使用它自己提供的页面,登录成功后也是默认的页面跳转,也可以自定义登录页面 mylogin.html:

<!DOCTYPE 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>Title</title>
</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!";
    }
}

启动项目:访问"/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<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();

    }

LogoutHandler的默认实现:
在这里插入图片描述

发布了716 篇原创文章 · 获赞 2079 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/cold___play/article/details/104217562