• Spring Security(4)


    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

     

    前面的方法中,除了login()方法能成功,另外两个都失败,并不是因为代码问题,而是Spring Security默认是通过Web页面来实现页面逻辑跳转的。但在前后端分离的开发模式中,页面跳转的逻辑后端已经无法直接控制了,而是通过返回状态码由前端来执行跳转。因此,需要对应用进行改造。

    首先自定义认证成功处理器,也就是实现AuthenticationSuccessHandler接口:

    复制代码
    /**
     * 自定义认证成功处理器
     *
     * @author 湘王
     */
    @Component
    public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                            Authentication authentication) throws IOException, ServletException {
            System.out.println("登录成功");
    
            // 前后端分离的调用方式
            response.setStatus(HttpStatus.OK.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("OK");
        }
    }
    复制代码

     

     

     

    接着来实现之前没有的认证失败处理器AuthenticationFailureHandler:

    复制代码
    /**
     * 自定义认证失败处理器
     *
     * @author 湘王
     */
    @Component
    public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                            AuthenticationException exception) throws IOException, ServletException {
            System.out.println("user or password error");
    
            // 前后端分离的调用方式
            response.setStatus(HttpStatus.OK.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("user or password error");
        }
    }
    复制代码

     

     

    再实现登出处理器LogoutSuccessHandler:

    复制代码
    /**
     * 自定义登出处理器
     *
     * @author 湘王
     */
    @Component
    public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
        @Override
        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                    Authentication authentication) throws IOException, ServletException {
            System.out.println("登出成功");
    
            // 前后端分离的调用方式
            response.setStatus(HttpStatus.OK.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("OK");
        }
    }
    复制代码

     

     

    然后修改之前的修改WebSecurityConfiguration,让过滤器中增加对这几个处理器的支持:

    复制代码
    // 控制逻辑
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
        http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class);
    
        http.authorizeRequests()
                .anyRequest().authenticated()
                // 设置自定义认证成功、失败及登出处理器
                .and().formLogin().loginPage("/login")
                .successHandler(successHandler).failureHandler(failureHandler).permitAll()
                .and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
                .logoutSuccessHandler(logoutSuccessHandler).permitAll()
                // 跨域访问
                .and().cors()
                .and().csrf().disable();
    }
    复制代码

     

     

    现在再次测试LoginController中的登录和登出操作,可以看到它们都能成功执行。目前权限已经做到了与Controller中的业务逻辑无关了。

     

    但是仅仅做到登录、登出操作肯定是不行的,这连Demo都不如。所以接下里,来看看一个比较核心的问题:用户角色是否有效(不然建角色表干嘛)。

    先在LoginController类中加入下面两个方法:

    复制代码
    @GetMapping("/admin")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public String admin() {
        return "admin有ROLE_ADMIN角色";
    }
    
    @GetMapping("/manager")
    @PreAuthorize("hasRole('ROLE_MANAGER')")
    public String manager() {
        return "manager有ROLE_MANAGER角色";
    }
    复制代码

     

     

    启动应用,运行postman时会发现:

    1、admin登录,访问localhost:8080/admin正常,但访问localhost:8080/manager就出现Forbidden错误;

    2、manager登录,访问localhost:8080/manager正常,而访问localhost:8080/admin也出现Forbidden错误。

    这说明用户角色权限已经起作用了,但显示Forbidden的方式不够友好。所以再来增加一个自定义处理器,也就是实现AccessDeniedHandler接口,让访问拒绝友好一些:

    复制代码
    /**
     * 自定义访问被拒绝
     *
     * @author 湘王
     */
    @Component
    public class CustomAccessDeniedHandler implements AccessDeniedHandler {
        @Override
        public void handle(HttpServletRequest request, HttpServletResponse response,
                           AccessDeniedException exception) throws IOException, ServletException {
            System.out.println("permission denied");
    
            // 前后端分离的调用方式
            response.setStatus(HttpStatus.OK.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("permission denied");
        }
    }
    复制代码

     

     

    然后同样地,要在WebSecurityConfiguration过滤器链中增加这个新增的过滤器:

    复制代码
    // 控制逻辑
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
        http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class);
    
        http.authorizeRequests()
            .anyRequest().authenticated()
            // 设置自定义认证成功、失败及登出处理器
            .and().formLogin().loginPage("/login")
            .successHandler(successHandler).failureHandler(failureHandler).permitAll()
            .and().logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
            .logoutSuccessHandler(logoutSuccessHandler).permitAll()
            // 配置无权访问的自定义处理器
            .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler)
            .and().cors()
            .and().csrf().disable();
    }
    复制代码

     

     

    再用postman进行测试的时候就能看到,现在的提示现在已经比刚才要友好了。

     

     


     

     

    感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

     

  • 相关阅读:
    MySql无法连接本地地址localhost
    买了一个1T的硬盘,却没有1T,坑人的商家
    【Linux基础】Linux云服务器(腾讯云、阿里云、华为云)环境部署 | 安装远程XShell | 基本账号管理(超详细教程)
    C++之红黑树
    二十四、W5100S/W5500+RP2040树莓派Pico<PHY的状态模式控制>
    Java语言中的泛型的概念和使用方法
    LeetCode:2304. 网格中的最小路径代价(C++)
    携职教育:一般纳税人资格证明如何打印?
    MySQL事务(清晰易懂)
    Node.js_基础知识(计算机硬件基础)
  • 原文地址:https://www.cnblogs.com/xiangwang1111/p/16920329.html