首页 > 编程语言 >开发手记-小程序请求被Spring Security权限认证拦截

开发手记-小程序请求被Spring Security权限认证拦截

时间:2023-05-10 15:22:40浏览次数:45  
标签:请求 登录 Spring 手记 Security 权限 ticket

场景描述

这是一个微信小程序向后端发送的请求,并且请求路径被后端Spring Security权限认证监控

这里Spring Security只负责权限不负责登录认证

问题

因为微信小程序本身不支持cookie机制,但是即使手动为请求带上了登录凭证字段ticket,请求依旧返回'用户未登录',接口功能不能调用

排查问题

反复尝试几次,排除请求字段等低级错误之后尝试以下做法

后端版本回滚,检查接口功能

为了做微信登陆以及适配微信小程序,开发过程中后端代码有所变更,以至于原本网页端可用的功能不可用

测试网页端相同功能请求接口,功能正常(涉及登录状态不能直接测接口)

自行设置的cookie字段是否生效

前端检查登录接口正常,也就是说:前端登录提交表单时匹配验证码携带的cookie是正常被后端接受了的,也就是cookie字段生效


结合网页端功能正常,基本确定问题出在后端

动态断点检查

通过在上面的Interceptor断点,确定了:

  1. 前置请求以及无须权限的请求都是进入并成功赋权了的,证实了不是ticket cookie字段的问题
  2. 出现问题的请求并没有进入Interceptor便直接返回了'用户未登录',证实了问题出在Spring Security
静态代码检查

整个过程涉及的流程大概是这样:

  1. 首先,位于Filter层的Spring Security会对请求做权限检查
  2. 其次,检查登录凭证的Interceptor会检查ticket并为之赋权
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从cookie中获取凭证
        String ticket = CookieUtil.getValue(request,"ticket");
        if (ticket!=null){
            // ...检查凭证是否有效
                Authentication authentication = new UsernamePasswordAuthenticationToken(
                        user,user.getPassword(),userService.getAuthorities(user.getId()));

                SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
            }
        }else SecurityContextHolder.clearContext();
        return true;
    }
  1. 最终到达aspect以及Controller层

猜想:流程问题

上述的整个认证验权的过程并不是简单线性的,一句话概括就是:当前请求权限取决于上一次请求,登录成功后需要一次无需权限请求刷新后续请求权限

怎么理解呢,首先登录请求肯定是无需权限也没有权限的,同时也没有登录凭证ticket,登录成功后,返回并给前端设置登录凭证ticket下次带上就能通过Interceptor的认证
但是!下一次请求仍旧是没有权限的,因为上述先Filter后Interceptor的机制,登录请求本身是没携带ticket,也就是说并没有完成Interceptor中的赋权过程
如果下一次请求是一个需要权限的请求,则会被Spring Security直接拦截
解决办法是我们会进行一次无需状态的请求,无需权限才能通过Spring Security,它携带上ticket在Interceptor中刷新用户权限,同时这个操作也会刷新页面,登录态的页面内容跟未登录的是不一样的,所以这个一举两得的做法很巧妙

于是我在小程序端实现了上述要求,但是很让人失望的是——报错仍在,还有别的问题

报错的位置

报错是在Spring Security的错误梳理处定义的

        http.exceptionHandling()
                // 没有登陆时的处理
                    response.setContentType("application/plain;charset=utf-8");
                    PrintWriter writer = response.getWriter();
                    writer.write(CommunityUtil.getJSONString(403, "用户未登录"));
                })

问题定位

我百思不得其解,于是第二天早上约了做小程序的同学,详细描述并讨论了这个问题
尽管我们两个对Spring Security都不是很熟悉,但是他还是指出:Spring Security是怎么知道你这次请求和上一次请求是同一个用户呢?
换言之,我意识到我无法回答的关键问题是:Spring Security是通过请求中的什么去匹配上下文中保存的凭据,并最终判断权限是否通过的呢?
继续检查请求并简单查阅资料后,我们把目光聚焦在了JSESSIONID字段(我并没有使用Session,而是用的Redis做分布式登录),我们猜想:Spring Secrity就是通过这个字段绑定了会话,并且正是由于这个字段的缺失导致了小程序请求被拦截
再通过多次构造请求试验后,我证实了这个猜想

寻找解决方案

标签:请求,登录,Spring,手记,Security,权限,ticket
From: https://www.cnblogs.com/yaocy/p/17388120.html

相关文章

  • SpringBoot 配置文件加载优先级
    我们在使用springboot开发的时候,经常会从外部获取属性值,为了记住这些规则,特此做如下记录~~~一、为什么要做外部化配置本地开发的时候,上传文件的时候,每个人想上传的路径不一样,使用外部配置,就可以单独设置自己的上传路径项目部署的时候,不同的环境使用不同的配置,使用外部挂载配置这......
  • spring boot中文件下载方法
     1、返回文件作为响应体,使用ResponseEntity类:@GetMapping("/downloadFile")publicResponseEntity<byte[]>downloadFile()throwsIOException{//读取文件内容到字节数组byte[]fileContent=Files.readAllBytes(Paths.get("path/to/file.txt"));......
  • spring 测试框架与维护项目结合问题
    之前项目中一直用junit进行单元测试,使用的版本一直是junit4.3版本(在junit库中,应该是自己定义的库)。由于springtest需要junit4.4,所以在工程的classpath中添加了junit4.4,运行时,报如下错误:Cannotfindtheclassfilefororg.junit.internal.runners.JUnit4ClassRunner。需要去除......
  • spring 2.5 TestContext 测试框架
    大多同事都已经养成用junit写单元测试的习惯,但junit在测试spring时,存在一些不足!1.  Spring容器多次初始化问题根据JUnit测试用例的调用流程,每执行一个测试方法都会重新创建一个测试用例实例并调用其setUp()方法。由于在一般情况下,我们都在setUp()方法中初始化Spring......
  • spring2.5 引入资源文件的方式
     以前项目中引入数据库连接相关的字符串都是使用<beanid="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <propertyname="locations"> <list> <value>classpath:fram......
  • SpringSecurity实战(二)-基于数据库认证
    pom依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId&......
  • SpringBoot定义优雅全局统一Restful API 响应框架四
    如果没有看前面几篇文章请先看前面几篇SpringBoot定义优雅全局统一RestfulAPI响应框架SpringBoot定义优雅全局统一RestfulAPI响应框架二SpringBoot定义优雅全局统一RestfulAPI响应框架三目前我们好像似乎解决所有问题,达到了我们理想的效果如下但是在业务错误返回时候......
  • Spring18_SpringMVC的组件解析3
    一、SpringMVC的执行流程1. 用户发送请求至前端控制器DispatcherServlet。2.DispatcherServlet收到请求调用HandlerMapping处理器映射器。3.处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给Dis......
  • spring框架_ApplicationContext实现
    ApplicationContext实现ApplicationContext有四个经典实现ClassPathXmlApplicationContext:经典容器,基于classpath下xml格式的配置文件来创建FileSystemXmlApplicationContext:基于磁盘路径下xml格式的配置文件前两种实现都是用来帮助beanfactory读取bean的都是读取XML......
  • SpringBoot+Redis+自定义注解实现接口防刷(限制不同接口单位时间内最大请求次数)
    场景SpringBoot搭建的项目需要对开放的接口进行防刷限制,不同接口指定多少秒内可以请求指定次数。比如下方限制接口一秒内最多请求一次。 注:博客:https://blog.csdn.net/badao_liumang_qizhi实现1、实现思路首先自定义注解,添加时间区间和最大请求次数字段。然后自定义......