Spring Security 基础教程 -- HttpSecurity 权限和登录表单配置

HttpSecurity 权限配置

主要是通过 HttpSecurity 配置访问控制权限,它仍是继承自 WebSecurityConfigurerAdapter ,重写其中的 configure(HttpSecurity http) 方法, 沿用上面的 SecurityConfig 类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 这是一个过期的方法
     * 指明密码不用加密
     */
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     * 定义两个用户,并设置密码和角色
     * 从 Spring5.0 开始,密码必须要加密
     * 基于内存的用户认证
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password("123456")
                .roles("admin")
                .and()
                .withUser("user1")
                .password("123")
                .roles("user");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 只有 admin 角色才能访问路径 /admin/**
                .antMatchers("/admin/**").hasRole("admin")
                // admin 和 user 角色都能访问路径 /user/**
                .antMatchers("/user/**").hasAnyRole("admin", "user")
                // 其他路径请求,只要是登录用户都可以访问
                .anyRequest().authenticated()
                .and()
                // 配置表单登录
                .formLogin()
                // 处理登录的 URL
                .loginProcessingUrl("/doLogin")
                // 与登录相关的请求都可以通过
                .permitAll()
                .and()
                // 关闭 csrf 保护
                .csrf().disable();
    }
}

通过 http.authorizeRequests().antMatchers("路径").hasRole("角色") ,赋予相应角色的路径访问权限。

HttpSecurity 登录表单配置

仍然沿用上面的configure(HttpSecurity http)方法。

登录成功

在前后端分离的项目中,登录成功后,后台向前台返回一个 json 字符串,表示登录成功,具体配置如下:

                // 登录成功后的处理
                .successHandler(new AuthenticationSuccessHandler() {
                    // authentication 保存了登录成功的用户信息
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        // 返回 json 格式的数据
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter writer = httpServletResponse.getWriter();
                        Map<String, Object> map = new HashMap<>(16);
                        map.put("status:", 200);
                        map.put("msg:",authentication.getPrincipal());
                        writer.write(new ObjectMapper().writeValueAsString(map));
                        writer.flush();
                        writer.close();
                    }
                })

效果如下图:

登录失败

登录失败后,后台仍向前台返回一个 json 字符串,并注明登录失败的原因。

登录失败后的具体配置如下:

                //登录失败后的处理
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter writer = httpServletResponse.getWriter();
                        Map<String, Object> map = new HashMap<>(16);
                        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:","登录失败!");
                        }
                        writer.write(new ObjectMapper().writeValueAsString(map));
                        writer.flush();
                        writer.close();
                    }
                })

效果如下:

对于登录失败后的各种情况,可以通过查看抽象类 AuthenticationException的继承关系,获悉所有的异常情况:

注销登录

仍然沿用上面的configure(HttpSecurity http)方法。

.permitAll()方法后,配置注销登录的信息:

                // 与登录相关的请求都可以通过
                .permitAll()
                // 注销登录的配置
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        // 返回 json 格式的数据
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter writer = httpServletResponse.getWriter();
                        Map<String, Object> map = new HashMap<>(16);
                        map.put("status:", 200);
                        map.put("msg:","注销登录成功!");
                        writer.write(new ObjectMapper().writeValueAsString(map));
                        writer.flush();
                        writer.close();
                    }
                })

注销登录是一个 get 请求,效果如下:

每天学习一点点,每天进步一点点。

posted @ 2020-11-02 15:06  爱吃西瓜的番茄酱  阅读(2032)  评论(0编辑  收藏  举报