通过zuul修改请求参数——对请求参数进行解密
zuul是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用,Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架,Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。zuul的核心是一系列的filters, 其作用可以类比Servlet框架的Filter,或者AOP。
在基于 springcloud 构建的微服务系统中,通常使用网关zuul来进行一些用户验证等过滤的操作,比如 用户在 header 或者 url 参数中存放了 token ,网关层需要 用该 token 查出用户 的 userId ,并存放于 request 中,以便后续微服务可以直接使用而避免再去用 token 查询。
在这里,使用zuul的过滤器对请求参数验签(解密),然后发给后续的微服务。
共三个服务:注册中心,zuul服务,通过zuul能访问到的服务。
流程:zuul服务和另一个服务注册到注册中心上,带有加密过得参数的请求url经过zuul处理参数解密之后发给后续微服务。
首先获取到request,但是在request中只有getParameter()而没有setParameter()方法,所以直接修改url参数不可行,另外在request中虽然可以setAttribute(),但是可能由于作用域(request)的不同,一台服务器才能getAttribute()出来,在这里设置的Attribute在后续的微服务中是获取不到的,因此必须考虑另外的方式:get方法和其他方法处理方式不同,post和put需重写HttpServletRequestWrapper,即获取请求的输入流,重写json参数,传入重写构造上下文中的request中。
zuul中的filter代码
import com.example.zuuldemo.util.AESUtil;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils; import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* 处理请求参数filter
*
* @author :liuqi
* @date :2018-08-29 14:11.
*/
@Component
public class SignFilter extends ZuulFilter { private static Logger log = LoggerFactory.getLogger(SignFilter.class); /**
* pre:路由之前
* routing:路由之时
* post: 路由之后
* error:发送错误调用
*
* @return
*/
@Override
public String filterType() {
return "pre";
} /**
* filterOrder:过滤的顺序
*
* @return
*/
@Override
public int filterOrder() {
return 0;
} /**
* shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
} /**
* run:过滤器的具体逻辑。
* 要把请求参数进行验签(解密)之后传给后续的微服务,首先获取到request,但是在request中只有getParameter()而没有setParameter()方法
* 所以直接修改url参数不可行,另外在reqeust中虽然可以使用setAttribute(),但是可能由于作用域(request)的不同,一台服务器中才能getAttribute
* 在这里设置的attribute在后续的微服务中是获取不到的,因此必须考虑另外的方式:即获取请求的输入流,并重写,即重写json参数,
* ctx.setRequest(new HttpServletRequestWrapper(request) {}),这种方式可重新构造上下文中的request
*
* @return
*/
@Override
public Object run() { // 获取到request
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
// 获取请求参数name
String name = "";
try { // 请求方法
String method = request.getMethod();
log.info(String.format("%s >>> %s", method, request.getRequestURL().toString()));
// 获取请求的输入流
InputStream in = request.getInputStream();
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
// 如果body为空初始化为空json
if (StringUtils.isBlank(body)) {
body = "{}";
}
log.info("body" + body);
// 转化成json
JSONObject json = JSONObject.fromObject(body); // get方法和post、put方法处理方式不同
if ("GET".equals(method)) { // 获取请求参数name
name = request.getParameter("name"); if (name != null) {
// 关键步骤,一定要get一下,下面才能取到值requestQueryParams
request.getParameterMap();
Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
if (requestQueryParams == null) {
requestQueryParams = new HashMap<>();
}
List<String> arrayList = new ArrayList<>();
String key = "key";
String aes_decodedStr = AESUtil.getInstance().decode(name, key);
arrayList.add(aes_decodedStr + "");
requestQueryParams.put("decodename", arrayList);
ctx.setRequestQueryParams(requestQueryParams);
}
}// post和put需重写HttpServletRequestWrapper
else if ("POST".equals(method) || "PUT".equals(method)) { // 获取请求参数name
name = json.getString("name"); if (name != null) { String key = "key";
// String aes_encodedStr = AESUtil.getInstance().encode(name, key);
// log.info("加密:" + aes_encodedStr);
// json.put("decodename", aes_decodedStr);
String aes_decodedStr = AESUtil.getInstance().decode(name, key);
log.info("解密:" + aes_decodedStr); // 把解密之后的参数放到json里
json.put("decodename", aes_decodedStr);
String newBody = json.toString();
log.info("newBody" + newBody);
final byte[] reqBodyBytes = newBody.getBytes(); // 重写上下文的HttpServletRequestWrapper
ctx.setRequest(new HttpServletRequestWrapper(request) {
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStreamWrapper(reqBodyBytes);
} @Override
public int getContentLength() {
return reqBodyBytes.length;
} @Override
public long getContentLengthLong() {
return reqBodyBytes.length;
}
});
}
} } catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
后续服务获取到解密后的参数
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Map; /**
* 接收经过zuul处理(解密)的参数,并返回
*
* @author :liuqi
* @date :2018-08-29 12:12.
*/
@RestController
public class HiController { /**
* get方式
* @RequestParam注解方式
*
* @param decodename
* @return
*/
@GetMapping("/hi")
public String getName(@RequestParam("decodename") String decodename){
return decodename;
} /**
* post方式
* @RequestBody注解方式获取
*
* @param param
* @return
*/
@PostMapping("/hello")
public String postName(@RequestBody Map<String,String> param){
String name = param.get("decodename");
return name;
} /**
* post方式
* 获取请求的输入流,并转化成json
*
* @param request
* @return
*/
@PostMapping("/hello1")
public String postName1(HttpServletRequest request){
String name = "";
try {
InputStream in = request.getInputStream();
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
if(StringUtils.isNotBlank(body)){
JSONObject jsonObject = JSONObject.fromObject(body);
name = (String)jsonObject.get("decodename");
}
} catch (IOException e) {
e.printStackTrace();
}
return name;
} /**
* post方式
* @RequestBody注解方式获取
*
* @param param
* @return
*/
@PutMapping("/howareyou")
public String putName(@RequestBody Map<String,String> param){
String name = param.get("decodename");
return name;
}
get请求测试
地址:http://localhost:1112/api-a/hi?name=5A0B6501B76A82FCAE5FC26DB2583B0D

post请求测试
http://localhost:1112/api-a/hello

put请求测试
地址:http://localhost:1112/api-a/howareyou

代码地址:https://github.com/yuki9467/zuul-handlerequest-demo
通过zuul修改请求参数——对请求参数进行解密的更多相关文章
- java 修改HttpServletRequest的参数或请求头
场景:过滤器中获取参数Token并添加到请求头(用户认证兼容老系统) 请求头和请求参数是不能直接修改,也没有提供修改的方法,但是可以在过滤器和拦截器中使用HttpServletRequestWrapp ...
- Zuul 修改 请求头、响应头 (死磕)
疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 架构师成长+面试必备之 高并发基础书籍 [Netty Zookeeper Redis 高并发实战 ] 前言 Crazy ...
- SpringMVC(二):RequestMapping修饰类、指定请求方式、请求参数或请求头、支持Ant路径
@RequestMapping用来映射请求:RequestMapping可以修饰方法外,还可以修饰类 1)SpringMVC使用@RequestMapping注解为控制指定可以处理哪些URL请求: 2 ...
- 【nginx笔记】系统参数设置-使Nginx支持更多并发请求的TCP网络参数
首先,需要修改/etc/sysctl.conf来更改内核参数.例如,最常用的配置: fs.file-max = 999999 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tc ...
- spring基础---->请求与响应的参数(一)
这里面我们主要介绍一下spring中关于请求和响应参数数据的问题.爱,从来就是一件千回百转的事.不曾被离弃,不曾受伤害,怎懂得爱人?爱,原来是一种经历. spring中的请求与响应 一.spring中 ...
- rest-assured之如何指定请求数据(Specifying Request Data 包括请求参数、请求头、cookie等)
我们除了可以为一个请求指定请求参数之外,还可以指定请求头(header).cookies.请求体(body)以及请求内容类型(content-type)等,下面我们就来一一介绍一下: 一.请求HTTP ...
- Django中获取参数(路径,查询,请求头,请求体)
一.通常HTTP协议向服务器传参有几种途径 : 提取URL的特定部分,如/weather/shanghai/2018,可以在服务器端的路由中用正则表达式截取: 查询字符串(query string), ...
- postman(十二):发送携带md5签名、随机数等参数的请求
想起来之前在借助百度翻译接口做翻译小工具的时候,需要把参数进行md5加密后再传输. 而在平时的接口测试工作中难免会遇到类似这种请求参数,比如md5加密.时间戳.随机数等等.固然可以先计算出准确的参数, ...
- postman+xmysql实现postman与数据库的交互,获取数据库的值来作为参数进行请求
安装nodejs和npm详细步骤:https://www.runoob.com/nodejs/nodejs-install-setup.html 安装xmysql 执行命令: npm install ...
随机推荐
- JDK常用命令行工具(基于JDK10)
虽然我是在jdk10环境下, 但是大体上和jdk8是差不多的. 总共有这么多 本来想着一口气把所有命令都边学边总结一下的, 结果发现....有些还真的不是很常用....或者说我这个水平还接触不到那么多 ...
- SQL数字型注入代码审计
数字型注入 SQL注入攻击,简称注入攻击,是发生于应用程序与数据库层的安全漏洞. 简而言之,是在输入的字符串之中注入sql指定,在设计不良的程序当中忽略了检查,那么这些注入进去的指令就会被数据库服务器 ...
- linxu上安装mongodb3.6实战
根据linux 版本到官网下载对应mongodb版本 查看服务器版本:cat /proc/version 查看linux发行版本:cat /etc/redhat-release 我用的阿里云服务器,对 ...
- python3 练手实例5 做一个简单电子时钟
import time,sys,os while(1): t = time.strftime('%Y-%m-%d\n%H:%M:%S',time.localtime(time.time())) pri ...
- 关于C的全局变量
一般来说,不会将全局变量的定义写在头文件中.因为如果多个C源文件都添加了头文件,很容易引起重复定义的问题,这时候一般编译器都会提示.正确的做法是在C源文件中定义一个全局变量,在头文件中加入全局变量的声 ...
- 最大K段和题解
题目:XJOI335 传送门 [ >XJOI<] 重要提示:您的膜法等级必须达到3级6段才可使用本传送门,否则您会被小猫痛扁 因为博主太懒,不提供题面(QAQ)... 很容易想到使用DP, ...
- python 机器学习三剑客 之 Matplotlib
Matplotlib介绍: Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形 . 通过 Matplotlib,开发者可以仅需要几 ...
- Python爬虫从入门到进阶(2)之urllib库的使用
1.什么是Urllib(官网地址:https://docs.python.org/3/library/urllib.html#module-urllib) Urllib是python内置的HTTP请求 ...
- c#串口编程(转)
在单片机项目开发中,上位机也是一个很重要的部分,主要用于数据显示(波形.温度等).用户控制(LED,继电器等),下位机(单片机)与 上位机之间要进行数据通信的两种方式都是基于串口的: USB转串口 — ...
- node命令行工具—cf-cli
音乐分享: 钢心 - <龙王> 初喜<冠军>后喜<龙王> (PS:听一次钢心乐队的演出后采访才知道 “龙王”隐喻的是一起喝酒的老铁....) ——————————— ...