• Spring Security进行权限控制


    一、SpringSecurity介绍

    • 简介
      SpringSecurity是一个专注于java应用程序提供身份认证和授权的框架,它的强大之处在于它可以轻松扩展以满足自定义的需求
    • 特征
      – 对身份的认证授权提供全面的、可扩展的支持。
      – 防止各种攻击,如会话固定攻击、点击劫持、csrf攻击等。
      – 支持与Servlet API,Spring MVC等web技术支持
    • SpringSecurity底层是通过11钟过滤器进行实现,属于JavaEE层面
      在这里插入图片描述
      SpringSecurity底层详解网站推荐:http://www.spring4all.com/article/428

    二、利用SpringSecurity进行权限控制

    引入依赖

    
        org.springframework.boot
        spring-boot-starter-security
    
    
    • 1
    • 2
    • 3
    • 4

    编写config类

    对未登录,权限不足以及退出时进行过滤

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter implements CommunityConstant {
        //忽略对静态资源的拦截
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/resources/**");
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //授权
            http.authorizeRequests()
                    //需要授权的请求
                    .antMatchers(
                            "/user/setting",
                            "/user/upload",
                            "/discuss/add",
                            "/comment/add/**",
                            "/letter/**",
                            "/notice/**",
                            "/like",
                            "/follow",
                            "/followee/**",
                            "/follower/**"
                    )
                    //上述请求需要的身份
                    .hasAnyAuthority(
                            AUTHORITY_USER,
                            AUTHORITY_ADMIN,
                            AUTHORITY_MODERATOR
                    )
                    //拥有身份时允许的行为
                    .anyRequest().permitAll();
    
            //权限不够时的操作
            http.exceptionHandling()
                    //没有登陆
                    .authenticationEntryPoint(new AuthenticationEntryPoint() {
                        @Override
                        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                            //当请求头是x-requested-with=XMLHttpRequest时说明是异步请求,返回JSON字符串
                            String xRequestedWith = request.getHeader("x-requested-with");
                            //if (xRequestedWith.equals("XMLHttpRequest")) {会报空指针异常
                            if ("XMLHttpRequest".equals(xRequestedWith)) {
                                response.setContentType("application/plain;charset=utf-8");
                                PrintWriter writer = response.getWriter();
                                writer.write(CommunityUtil.getJSONString(403, "您还没有登录!"));
                            } else {
                                response.sendRedirect(request.getContextPath() + "/login");
                            }
                        }
                    })
                    //权限不足
                    .accessDeniedHandler(new AccessDeniedHandler() {
                        @Override
                        public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                            //当请求头是x-requested-with=XMLHttpRequest时说明是异步请求,返回JSON字符串
                            String xRequestedWith = request.getHeader("x-requested-with");
                            //if (xRequestedWith.equals("XMLHttpRequest")) {会报空指针异常
                            if ("XMLHttpRequest".equals(xRequestedWith)) {
                                response.setContentType("application/plain;charset=utf-8");
                                PrintWriter writer = response.getWriter();
                                writer.write(CommunityUtil.getJSONString(403, "您没有访问的权限!"));
                            } else {
                                response.sendRedirect(request.getContextPath() + "/denied");
                            }
                        }
                    });
            //security底层默认会拦截/logout请求,进行退出处理,覆盖他的逻辑,才能执行我们自己的推出代码
            http.logout().logoutUrl("/securitylogout");//写一个没有的请求欺骗springSecurity
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    if (xRequestedWith.equals(“XMLHttpRequest”)) 会报空指针异常,因为xRequestedWith可能为null
    改为if (“XMLHttpRequest”.equals(xRequestedWith)) 防止此错误

    编写userService类实现获取用户权限的方法

    @Override
    public Collection getAuthorities(int userId) {
        //获得当前登录用户
        User user = this.findUserById(userId);
        //将用户权限装入List
        List list = new ArrayList<>();
        list.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                switch (user.getType()){
                    case 1:
                        return AUTHORITY_ADMIN;
                    case 2:
                        return AUTHORITY_MODERATOR;
                    default:
                        return AUTHORITY_USER;
                }
            }
        });
        return list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    将认证信息写入过滤器

    写入过滤器的preHandle方法,在每一次请求前都调用

    //构建用户认证的结果,并存入SecurityContext,以便于security进行授权
    Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), userService.getAuthorities());
    SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
    
    • 1
    • 2
    • 3

    并在请求结束时的afterCompletion方法中清楚认证

    SecurityContextHolder.clearContext();
    
    • 1

    防止csrf攻击

    在这里插入图片描述

    • csrf攻击:
      在用户提交表单时,不法网站可能窃取用户提交的信息进行提交从而造成安全问题

    • 解决办法
      springsecurity中在用户同步提交表单时设置了一个隐藏的token,不但会对用户提交的信息进行核实,还会对token进行核实,在异步提交的时候则需要自行在前端加入token提交

    • 异步请求时徐手动添加token的提交

      //发送ajax请求前,将csrf令牌设置到请求的消息头中
      var token = $(“meta[name=‘_csrf’]”).attr(“content”);
      var header = $(“meta[name=‘_csrf_header’]”).attr(“content”);
      $(document).ajaxSend(function (e, xhr, options) {
      xhr.setRequestHeader(header, token)
      })

    在这里插入图片描述
    添加成功

    三、整合前端模板

    引入依赖

    
        org.thymeleaf.extras
        thymeleaf-extras-springsecurity5
    
    
    • 1
    • 2
    • 3
    • 4

    前端引入

    
    
    • 1

    模块设置

    
    
    • 1

    满足moderator权限时才显示

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    如何删除重复文件?简单操作法方法盘点!
    基于MATLAB的电流、电压互感器特性的仿真分析
    安全认证 | CISSP和CISP,傻傻分不清楚?
    智能语音机器人竞品调研
    【JavaSE】认识异常(上篇)
    【五一创作】使用Scala二次开发Spark3.3.0实现对MySQL的upsert操作
    JavaScript 中整数的安全范围
    【数据结构】——并查集 的 详细解析和实现
    MySQL常见面试题
    C++运算符重载+,*在QT中的实现演示
  • 原文地址:https://blog.csdn.net/geejkse_seff/article/details/126114169