spring cloud项目微服务间互相调用使用自定义标注进行鉴权方案

来吧,贴代码。

一、背景

我们有一个项目使用了spring cloud,有的微服务需要调用别的微服务,但这些调用没有鉴权;当初项目时间非常紧,同时这部分微服务有的对外也没有鉴权,在代码中设置了无须鉴权,可直接访问。近期客户进行安全性测评,查出了一堆安全性漏洞。你睇下:

@Override
public void configure(HttpSecurity http) throws Exception {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests()//添加放行接口,不进行OAuth2授权认证.antMatchers("/camera/**","/jcDeviceManufacturer/file/preview/**","/jcStationFile/**","/jcTimedTask/**","/jcDevice/**","/jcStation/**","/user/query/warning/**","/jcSenorDataCurrent/**","/jcSensorData003/**","/jcSensorData007/**","/jcSensorData008/**","/jcSensorData009/**","/jcSensorData012/**","/jcSensorData014/**","/jcSensorData015/**","/jcSensorData024/**","/jcSensorData025/**","/jcSensorData027/**","/jcSensorData034/**","/jcSensorGnssResolvedata/**","/jcSensorDataDxs/**","/jcSensorDataGnss/**","/jcStationMap/**","/jcWarnConfigDevice/**","/jcStationDeviceMap/**").permitAll()// 指定监控访问权限.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll().anyRequest().authenticated().and()//认证鉴权错误处理.exceptionHandling().accessDeniedHandler(new OpenAccessDeniedHandler()).authenticationEntryPoint(new OpenAuthenticationEntryPoint()).and().csrf().disable();
}

如之奈何,计将安出?

二、思路

项目早就验收了,维护期也过期了。本着为客户着想,并幻想他们能再续期,丢个几万元让我们维护,所以我奋不顾身地维护一下。

我的指导原则是代码不要进行大的调整,尽量简单处理,毕竟量体裁衣,看菜吃饭。而且当时项目开发的人很多,我只负责其中几个模块,好多都不是我弄的。现在人员已经走得差不多了,维护任务就落到我头上。我只好硬着猪头皮,献上思路如下:

1)微服务间调用,检查请求头有无带上特定信息,有则通过,无则抛出异常
2)外部访问,设置白名单,检查发出请求的IP,符合则通过,否则抛出异常。这样第三方系统就不用更改了
3)但这些服务中,有一些前端也会请求。由于前端有登录,那么前端的请求应该不受上面的限制措施影响。
4)搞一个标注来完成这些鉴权动作,并且应用AOP,尽量将现有代码改动减到最小。

三、具体实现

1、标注@Inner,用于标记类

import java.lang.annotation.*;/*** 微服务内部访问方法*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Inner {/*** 是否AOP统一处理*/boolean value() default true;
}

2、标注@InnerMethod,用于标记方法

import java.lang.annotation.*;/*** 微服务内部访问方法*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InnerMethod {/*** 是否AOP统一处理*/boolean value() default true;
}

3、AOP

1)InnerAspect.java

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;@Aspect
@Component
public class InnerAspect implements Ordered {
/**
配置文件内容:
inner.head.name=X-From
inner.head.value=internal
inner.white-ip=127.0.0.1,192.168.10.8,192.168.10.9
*/@Value(value = "${inner.head.name:X-From}")private String from;@Value(value = "${inner.head.value:internal}")private String fromIn;@Value(value = "${inner.white-ip:127.0.0.1}")private String whiteIps;private static List<String> whiteList = null;@Around("@within(inner)")  // Modified pointcut expressionpublic Object around(ProceedingJoinPoint point, Inner inner) throws Throwable {if(!isValid(point,inner.value())){throw new AccessDeniedException("Access is denied");}return point.proceed();  // Proceed with the original method call}/*** 注意 @Around("@annotation(innerMethod)")中的"innerMethod",* 名称要与aroundMethod(ProceedingJoinPoint point, InnerMethod innerMethod) 中的参数名称一致* @param point* @param innerMethod* @return* @throws Throwable*/@Around("@annotation(innerMethod)")public Object aroundMethod(ProceedingJoinPoint point, InnerMethod innerMethod) throws Throwable {if(!isValid(point,innerMethod.value())){throw new AccessDeniedException("Access is denied");}return point.proceed();}@Overridepublic int getOrder() {return Ordered.HIGHEST_PRECEDENCE + 1;}private boolean isValid(ProceedingJoinPoint point, boolean innerHasValue){boolean yes = true;Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null || "anonymousUser".equals(authentication.getPrincipal())){//尚未登录initWhiteList();Signature signature = point.getSignature();if (innerHasValue) {  // Check if AOP is enabled for the classHttpServletRequest request = ServletUtils.getRequest();String header = request.getHeader(from);String ipAddress = getOriginalIp(request);// Authorization check based on request header or IP addressif (!fromIn.equals(header) && !whiteList.contains(ipAddress)) {System.err.println(String.format("没有权限访问接口 %s", signature.getName()));yes = false;}}}return yes;}private void initWhiteList(){if(whiteList == null || whiteList.size() == 0){whiteList = new ArrayList<>(Arrays.asList(whiteIps.split(",")));}}/*** 获取最原始的请求IP* 因为请求有可能经过nginx等转发* @param request* @return*/private String getOriginalIp(HttpServletRequest request) {String originalIp = request.getHeader("X-Forwarded-For");if (originalIp == null || originalIp.isEmpty()) {originalIp = request.getRemoteAddr();} else {// 可能会有多个IP,获取第一个IP地址originalIp = originalIp.split(",")[0].trim();}return originalIp;}
}

其中,主要逻辑部分:

private boolean isValid(ProceedingJoinPoint point, boolean innerHasValue){boolean yes = true;Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null || "anonymousUser".equals(authentication.getPrincipal())){//尚未登录initWhiteList();Signature signature = point.getSignature();if (innerHasValue) {  // Check if AOP is enabled for the classHttpServletRequest request = ServletUtils.getRequest();String header = request.getHeader(from);String ipAddress = getOriginalIp(request);// Authorization check based on request header or IP addressif (!fromIn.equals(header) && !whiteList.contains(ipAddress)) {System.err.println(String.format("没有权限访问接口 %s", signature.getName()));yes = false;}}}return yes;
}

首先看是否已经登录,未登录的话才进行考察。如果既无请求头,又不在白名单内,才抛出异常;否则都通过,宽松得很。

值得一提得是,@Around的写法。里面的参数要跟函数的参数保持一致:
在这里插入图片描述

2)自定义的HttpServletRequest.java

上面代码中用到这个自定义类。

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;public class ServletUtils {public static HttpServletRequest getRequest() {return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();}
}

四、使用

1、被调用的服务

1)类

@Api(value = "监测设备信息", tags = "监测设备信息")
@RestController
@RequestMapping("jcDevice")
@Inner
public class JcDeviceController implements IJcDeviceServiceClient {
。。。
}

2)方法

  @GetMapping("/file/preview")@InnerMethodpublic void previewDemo(HttpServletRequest request, HttpServletResponse response, @RequestParam("code") String code) {
。。。}

2、主动发起调用的服务

服务之间是通过Feign来调用的,只要在主动发起调用的微服务中实现Feign的拦截器即可:

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class InnerAuthInterceptor implements RequestInterceptor {@Value(value = "${inner.head.name:X-From}")private String from;@Value(value = "${inner.head.value:internal}")private String fromIn;@Overridepublic void apply(RequestTemplate template) {template.header(from, fromIn);}
}

五、小结

上述代码中,IP白名单在本地是没有问题的。但请求的转发是vue开发环境下实现的。部署到生产服务器nginx上,就拿不到最原始的请求IP,拿到的都是nginx服务器的IP。这个问题下周有时间再看看。

但不一定有时间。公司没啥活,员工却还是那么忙,搞不懂。
在这里插入图片描述
在这里插入图片描述

参考文章:
服务之间调用还需要鉴权?

Feign的拦截器RequestInterceptor

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/763374.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字节跳动面试被拷打:高效处理大量数据的JavaScript技巧

一、文章内容 时间分片宏任务微任务前置内容实现时间分片 二、时间切片 什么是时间切片&#xff1f;通过字面意思我们不难理解时间切片就是将时间分成多个片段进行一一渲染数据,时间切片是个抽象的问题,我们可能会想到JavaScript中window自带的setTimeout的延迟函数或者是 w…

Docker进阶教程 - 2 Docker部署SpringBoot项目

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 2 Docker部署SpringBoot项目 已经学习了 Dockerfile 了&#xff0c;下面介绍一下如何将 SpringBoot 项目通过 Dockerfile 来部署到 Docker 中。 1 修改项目配置 首先需要准备一个 SpringBo…

初识二叉树

文章目录 一.什么是树二.什么是二叉树三.二叉树的访问次序四.特殊的二叉树五.求结点个数六.平衡二叉树总结 一.什么是树 树是由一个集合以及在该集合上定义的一种关系构成的。 集合中的元素称为树的节点&#xff0c;所定义的关系称为父子关系。 父子关系在树的节点之间建立了一…

安装OneNote for Win10 | Win10/Win11

前言 PC端的OneNote分为2个版本&#xff0c;分别是Microsoft Store版本和Office版本&#xff0c;Microsoft Store版本即为OneNote for Win10&#xff0c;此版的OneNote有最近笔记功能&#xff0c;但检索功能不如Office版本&#xff0c;个人认为2个版本各有优劣。 但OneNote f…

新人应该从哪几个方面掌握大数据测试?

什么是大数据 大数据是指无法在一定时间范围内用传统的计算机技术进行处理的海量数据集。 对于大数据的测试则需要不同的工具、技术、框架来进行处理。 大数据的体量大、多样化和高速处理所涉及的数据生成、存储、检索和分析使得大数据工程师需要掌握极其高的技术功底。 需要你…

nodejs中使用@maxmind/geoip2-node 查询地理位置信息

介绍 maxmind/geoip2-node 是一个Node.js模块&#xff0c;用于与MaxMind的GeoIP2数据库进行交互&#xff0c;从而获取IP地址的地理位置信息。MaxMind的GeoIP2数据库包含了全球范围内的IP地址和对应的地理位置信息&#xff0c;如国家、城市、经纬度等。使用maxmind/geoip2-node…

Python连接MariaDB数据库

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;【持续更新最新版】-CSDN博客 Python连接MariaDB数据库 一、安装mariadb库 pip install mariadb 二、连接…

机器视觉学习(六)—— 图像的颜色识别

目录 一、色彩空间 1.1 RGB色彩空间 1.2 HSV色彩空间 1.3 灰度 1.4 CMYK色彩空间 1.5 Lab色彩空间 二、色彩空间转换 三、识别颜色 3.1 识别一种特定的颜色 3.2 识别多种颜色 一、色彩空间 计算机视觉中常用的色彩空间有RGB色彩空间、HSV色彩空间、CMYK色彩空间、La…

34-Java传输对象模式 ( Transfer Object Pattern )

Java传输对象模式 实现范例 传输对象模式&#xff08;Transfer Object Pattern&#xff09;用于从客户端向服务器一次性传递带有多个属性的数据传输对象也被称为数值对象&#xff0c;没有任何行为传输对象是一个具有 getter/setter 方法的简单的 POJO 类&#xff0c;它是可序列…

解锁AI之门:协助探索Amazon Bedrock服务

AI愈加强大的功能和广泛的应用场景&#xff0c;正逐渐改变着我们的工作和生活方式。 Amazon Bedrock在AI的时代潮流中&#xff0c;也以其强大而灵活的功能特性&#xff0c;正在成为越来越多企业和个人的智能助手。 亚马逊云科技通过VERYCLOUD睿鸿股份的服务能力&#xff0c;使…

揭秘!自定义三维模型如何在RflySim中实现仿真(一)

一.技术背景 在无人系统研发过程中&#xff0c;需要进行大量的运动控制系统半物理实时仿真实验&#xff0c;传统仿真界面的运动轨迹显示多采用的是二维曲线形式&#xff0c;运动过程和状态是通过文本数据显示。随着数据量的增加&#xff0c;该方式缺乏直观性&#xff0c;不易观…

python四川火锅文化网站的设计与实现flask-django-php-nodejs

四川火锅文化网站的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&#xff0c;…

蓝桥杯单片机快速开发笔记——特训2 按键的长按与短按

一、题目要求 在CT107D单片机综合训练平台上&#xff0c;通过I/O模式编写代码&#xff0c;实现以下功能&#xff1a; 系统上电后&#xff0c;关闭蜂鸣器、继电器和全部指示灯&#xff0c;数码管显示初始值为28&#xff0c;仅显示数码管最右边两位。利用定时器0实现10ms间隔定…

预测一下,GPT-5 会在什么时候发布,又会有哪些更新?

发布预期&#xff1a;GPT-5预计将于11月发布&#xff0c;可能与ChatGPT发布两周年同期。竞争态势&#xff1a;谷歌的Gemini与GPT-4 turbo已展开竞争。逐步发布&#xff1a;GPT-5可能通过模型训练过程中的中间检查点逐步发布。训练与安全测试&#xff1a;实际训练可能需3个月&am…

发布 AUR 软件包 (ArchLinux)

首发日期 2024-03-09, 以下为原文内容: 理论上来说, 我们应该平等的对待每一个 GNU/Linux 发行版本. 但是, 因为窝日常使用 ArchLinux, 所以对 ArchLinux 有一些特别的优待, 比如自己做的软件优先为 ArchLinux 打包发布. 本文以软件包 librush-bin 为例, 介绍发布 AUR 软件包的…

【IC设计】Verilog线性序列机点灯案例(四)(小梅哥课程)

文章目录 该系列目录&#xff1a;设计环境设计目标设计思路RTL及Testbench代码RTL代码Testbenchxdc约束 仿真结果 声明&#xff1a;案例和代码来自小梅哥课程&#xff0c;本人仅对知识点做做笔记&#xff0c;如有学习需要请支持官方正版。 该系列目录&#xff1a; Verilog线性…

力扣热门算法题 52. N 皇后 II,53. 最大子数组和,54. 螺旋矩阵

52. N 皇后 II&#xff0c;53. 最大子数组和&#xff0c;54. 螺旋矩阵&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.20 可通过leetcode所有测试用例。 目录 52. N 皇后 II 解题思路 完整代码 Python Java 53. 最大子数组…

长安链开源社区发布2023年度长安链优秀应用案例

1月27日结束的“长安链发布三周年庆暨生态年会”上&#xff0c;在国家区块链技术创新中心的指导下&#xff0c;长安链开源社区联合长安链生态联盟正式发布2023年度长安链行业示范案例、领域精品案例及特色创新案例。 本次评选面向2023年度应用长安链上线并取得应用成效的案例&…

Matlab在高光谱遥感中的作用:从数据处理到决策支持

光谱和图像是人们观察世界的两种方式&#xff0c;高光谱遥感通过“图谱合一”的技术创新将两者结合起来&#xff0c;大大提高了人们对客观世界的认知能力&#xff0c;本来在宽波段遥感中不可探测的物质&#xff0c;在高光谱遥感中能被探测。以高光谱遥感为核心&#xff0c;构建…

vue中如何实现子组件相互切换,而且数据不会丢失

项目场景&#xff1a; 今天的项目场景: 项目为数据报表,但是一个父页面中有很多的子页面,而且子页面中不是相互关联,但是数据又有联系. 问题描述 子页面相互切换的时候之前填写好的数据会丢失,无法保存.这样想提交所有的子页面的数据就出现问题. 原因分析&#xff1a; 分析原因…