首页 文章 精选 留言 我的

精选列表

搜索[身份验证],共2798篇文章
优秀的个人博客,低调大师

springboot中拦截并替换token来简化身份验证

一、场景来源 在日常开发实践中,时常需要使用工具(如 Postman、curl命令)来构建http请求进行 开发和测试,当遇到需要token鉴权的接口时,可能需要额外的页面登录或者请求其它接口来获取token,若开发测试过程中需要频繁切换账号时,一直手动获取token就是慢动作了。那么,这个操作是可以优化的吗? 项目环境:springboot + web + dubbo 请求示意:token放在header的token字段中 特别注意:这种方法仅能用于测试环境,切勿部署到线上!!! 二、期望 当构建的http请求指向的是开发测试环境时,不需要手动去获取token,只需提供用户身份标识(如用户名、手机号)即可自动获取并替换token(服务侧执行,不依赖具体使用的请求构建工具)。 三、限制 不能在代码提交记录上留下痕迹 需要兼容旧逻辑,不影响正常功能 不依赖具体业务逻辑,尽可能通用 四、实现方案 1.请求的简要链路 为了不修改原有的业务逻辑,所以需要在请求进入 业务代码 前,就把真正可用的token替换到header的token字段中,而兑换token则需要用户标识,所以用户标识也需要传递,由此可以列出几个点: 2.用户标识从哪里传递过来呢? 直接使用原有的token字段,并使用特殊前缀,如username、phone 3.在哪里对token进行替换呢? 为了不关联具体的业务代码,所以token需要在springMVC框架流程中进行替换,通过断点可以容易找到解析header的地方,只要在header报文解析完成之后并且可以获取到header对象的地方进行替换即可。 如:org.apache.coyote.http11.Http11InputBuffer#parseHeaders 4.如何使用用户标识来兑换token呢? 这个跟所使用的用户体系强相关的,看提供的是怎样的获取方式,本文的场景是调用dubbo接口即可进行兑换。如: 5.增加拦截点后的请求链路 五、实现步骤 1.token拦截点的实现: 由上面分析可知,拦截点是org.apache.coyote.http11.Http11InputBuffer#parseHeaders ,只要使用 try finally 块对整个方法的body进行包围,并且把识别和替换token的逻辑放在 finally 块中即可。 示意: javaassist实现: Tips:将token相关操作都封装到一个静态方法里边,编写插桩逻辑的时候会方便很多! 2.token的兑换: 由上边分析可知,token的兑换需要调用dubbo接口,但是我们选择的token拦截替换点并不是一个bean的方法,也没有dubbo接口的上下文,只是一个实例方法,那么要怎么调用dubbo接口呢? a.泛化调用【不采用】 比较麻烦,而且也需要读取相应的配置,而且会创建额外的dubbo接口对象,不予采用 b.将dubbo实例暴露到 static 【就你了】 通过跟踪@Reference注解的处理过程可以发现,所有动态生成的dubbo接口代理类都会存放在 com.alibaba.dubbo.config.spring.AnnotationBean中的referenceConfigs字段中: 并且com.alibaba.dubbo.config.spring.AnnotationBean是一个一个bean!!! 只要我们能获取到该bean,获取bean字段中的dubbo代理类还不手到擒来! 但是,拦截点处也没有bean的上下文呀! I.将bean暴露到 static 这个比较简单,只要在代码中获取到 ApplicationContext,并且赋值给一个静态字段即可, 如下:利用 org.springframework.context.ApplicationContextAware 然后再使用 spring.factories 让 @Component 生效,如下: 获取到bean后,还需要获取到dubbo为@Reference生成的实例才行 II.从bean中获取dubbo实例 源码可见com.alibaba.dubbo.config.spring.AnnotationBean中的referenceConfigs字段是private的,所以要用下反射,如下: dubbo接口已经准备好了,还需要加上具体的处理逻辑 3.拦截处理逻辑 这一步需要拦截特定格式的token,取出身份标识并调用dubbo兑换token,然后替换掉原来在header中的token即可 六、Running 经过上边的努力,就可以进行javaagent打包来运行了! Tips:打包javaagent可以使用 jar-with-dependencies 把依赖一起打包进去,并且当javaagent中的类需要依赖目标应用中的类或依赖时,其pom的scope需要声明为 provided,不然会把这部分依赖也打包进去 1.idea run【success】 配置javaagent: 在 Idea run config 中的vmoption加上javaagent参数 -javaagent:/path/to/agent/intercept-token-1.0-SNAPSHOT-jar-with-dependencies.jar 复制代码 Arthas看下插桩情况: perfect!!! Tips:如果你不使用jar-in-jar/nested-jars(使用springboot的jar打包插件)的方式部署项目,那么到这里已经可以了~ 2.部署到测试环境试 run【fail】 既然 idea 跑成功了,那就部署 测试环境(打包镜像并部署到容器中,用的是springboot的jar打包插件,将逻辑和依赖打包到一个jar包)中试试吧! 启动参数示例: /Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Home/bin/java \ -Dserver.port=9060 \ -javaagent:/path/to/agent/intercept-token-1.0-SNAPSHOT-jar-with-dependencies.jar \ -jar \ /path/to/springboot-application.jar 复制代码 报错: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'methodValidationPostProcessor' defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: Unsatisfied dependency expressed through method 'methodValidationPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [com.wingli.agent.helper.util.SpringContextHolder] for bean with name 'com.wingli.agent.helper.util.SpringContextHolder': problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContextAware at ...... Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [com.wingli.agent.helper.util.SpringContextHolder] for bean with name 'com.wingli.agent.helper.util.SpringContextHolder': problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContextAware at ...... Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContextAware at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[?:1.8.0_251] at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[?:1.8.0_251] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355) ~[?:1.8.0_251] at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[?:1.8.0_251] at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_251] at java.lang.ClassLoader.defineClass(ClassLoader.java:756) ~[?:1.8.0_251] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_251] at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) ~[?:1.8.0_251] at java.net.URLClassLoader.access$100(URLClassLoader.java:74) ~[?:1.8.0_251] at java.net.URLClassLoader$1.run(URLClassLoader.java:369) ~[?:1.8.0_251] at java.net.URLClassLoader$1.run(URLClassLoader.java:363) ~[?:1.8.0_251] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_251] at java.net.URLClassLoader.findClass(URLClassLoader.java:362) ~[?:1.8.0_251] at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[?:1.8.0_251] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355) ~[?:1.8.0_251] at java.lang.ClassLoader.loadClass(ClassLoader.java:405) ~[?:1.8.0_251] at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94) ~[study-minder.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[?:1.8.0_251] at org.springframework.util.ClassUtils.forName(ClassUtils.java:251) ~[spring-core-4.3.20.RELEASE.jar!/:4.3.20.RELEASE] at ...... 复制代码 why? 为什么会报这个错误呢? 为什么直接idea运行没有问题,为什么使用springboot插件的打包方式运行就报错了呢? 详情请见下回分解->Springboot上运行javaagent时出现NoClassDefFoundError错误的分析和解决 最后 如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑 如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http://github.crmeb.net/u/defu不胜感激! PHP学习手册:https://doc.crmeb.com 技术交流论坛:https://q.crmeb.com

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册