背景

将zuul网关作为认证入口,但是下游服务需要用户id,此时有两种解决方案。
1:将token 放入header中,在每次需要的时候去解析。(同时也是缺点,浪费资源)
2:在网关认证完成后,会获取到用户信息,将用户id放入参数中,若是本身也有userid,可以修改掉userid,同时也防止了登录用户获取到或修改其他用户的系统信息。(优点多,缺点有可能需要修改认证逻辑)

所以我们采用第二种(我设计的项目就是用的这种方案)

代码

注意,Get请求和post请求,分别修改的是url参数和body参数,所以两种处理方案是不一样的。以下分别为处理url参数和body参数的方案。

  1. import com.alibaba.fastjson.JSON;
  2. import com.boya.common.util.RequestUtils;
  3. import com.netflix.zuul.ZuulFilter;
  4. import com.netflix.zuul.context.RequestContext;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.lang3.StringUtils;
  7. import org.springframework.security.core.Authentication;
  8. import org.springframework.security.core.context.SecurityContext;
  9. import org.springframework.security.core.context.SecurityContextHolder;
  10. import org.springframework.stereotype.Component;
  11. import javax.servlet.http.HttpServletRequest;
  12. import java.util.ArrayList;
  13. import java.util.HashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import static com.netflix.zuul.context.RequestContext.getCurrentContext;
  17. @Component
  18. @Slf4j
  19. public class GetRequestFilter extends ZuulFilter {
  20. //定义filter的类型,有pre、route、post、error四种
  21. @Override
  22. public String filterType() {
  23. return "route";
  24. }
  25. //定义filter的顺序,数字越小表示顺序越高,越先执行
  26. @Override
  27. public int filterOrder() {
  28. return 6;
  29. }
  30. //表示是否需要执行该filter,true表示执行,false表示不执行
  31. @Override
  32. public boolean shouldFilter() {
  33. HttpServletRequest req = RequestContext.getCurrentContext().getRequest();
  34. if (StringUtils.equalsIgnoreCase(req.getMethod(), "get")) {
  35. log.info("Get 请求的url : " + req.getRequestURI().toString());
  36. return true;
  37. }
  38. return false;
  39. }
  40. public Object run() {
  41. SecurityContext context = SecurityContextHolder.getContext();
  42. Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  43. String currentPrincipalName = authentication.getName();
  44. RequestContext ctx = getCurrentContext();
  45. HttpServletRequest request = ctx.getRequest();
  46. if (log.isDebugEnabled()) {
  47. log.debug(String.format("当前用户: %s", currentPrincipalName));
  48. log.debug(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
  49. }
  50. Map<String, String[]> requestParameterMap = request.getParameterMap();
  51. if (log.isDebugEnabled()) {
  52. log.debug(String.format("header 参数 >>> %s", JSON.toJSONString(RequestUtils.getHeaders(request))));
  53. log.debug(String.format("request 参数 >>> %s", JSON.toJSONString(requestParameterMap)));
  54. }
  55. Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
  56. if (requestQueryParams == null) {
  57. requestQueryParams = new HashMap<>();
  58. }
  59. //将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去
  60. ArrayList<String> arrayList = new ArrayList<>();
  61. arrayList.add(currentPrincipalName);
  62. requestQueryParams.put("userId", arrayList);
  63. ctx.setRequestQueryParams(requestQueryParams);
  64. return null;
  65. }
  66. }
  1. import com.alibaba.fastjson.JSON;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.netflix.zuul.ZuulFilter;
  4. import com.netflix.zuul.context.RequestContext;
  5. import com.netflix.zuul.http.ServletInputStreamWrapper;
  6. import lombok.extern.slf4j.Slf4j;
  7. import org.apache.commons.lang3.StringUtils;
  8. import org.springframework.security.core.Authentication;
  9. import org.springframework.security.core.context.SecurityContext;
  10. import org.springframework.security.core.context.SecurityContextHolder;
  11. import org.springframework.stereotype.Component;
  12. import org.springframework.util.StreamUtils;
  13. import javax.servlet.ServletInputStream;
  14. import javax.servlet.http.HttpServletRequest;
  15. import javax.servlet.http.HttpServletRequestWrapper;
  16. import java.io.IOException;
  17. import java.io.InputStream;
  18. import java.nio.charset.Charset;
  19. import java.util.*;
  20. import java.util.stream.Collectors;
  21. import static com.netflix.zuul.context.RequestContext.getCurrentContext;
  22. @Component
  23. @Slf4j
  24. public class BodyParamerFilter extends ZuulFilter {
  25. static String principalParamName = "userId";
  26. //定义filter的类型,有pre、route、post、error四种
  27. @Override
  28. public String filterType() {
  29. return "route";
  30. }
  31. //定义filter的顺序,数字越小表示顺序越高,越先执行
  32. @Override
  33. public int filterOrder() {
  34. return 7;
  35. }
  36. //表示是否需要执行该filter,true表示执行,false表示不执行
  37. @Override
  38. public boolean shouldFilter() {
  39. HttpServletRequest req = RequestContext.getCurrentContext().getRequest();
  40. if (StringUtils.equalsIgnoreCase(req.getMethod(), "post") || StringUtils.equalsIgnoreCase(req.getMethod(), "post")) {
  41. log.info("非Get请求的url = " + req.getRequestURI().toString());
  42. return true;
  43. }
  44. return false;
  45. }
  46. public Object run() {
  47. SecurityContext securityContext = SecurityContextHolder.getContext();
  48. Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  49. String currentPrincipalName = authentication.getName();
  50. RequestContext context = getCurrentContext();
  51. HttpServletRequest request = context.getRequest();
  52. if (log.isDebugEnabled()) {
  53. log.debug(String.format("当前用户: %s", currentPrincipalName));
  54. log.debug(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
  55. }
  56. InputStream in = (InputStream) context.get("requestEntity");
  57. if (in == null) {
  58. try {
  59. in = context.getRequest().getInputStream();
  60. } catch (IOException e) {
  61. e.printStackTrace();
  62. }
  63. }
  64. log.info("accessToken:" + currentPrincipalName);
  65. log.info("params:" + context.getRequestQueryParams());
  66. log.info("contentLength:" + context.getRequest().getContentLength());
  67. log.info("contentType:" + context.getRequest().getContentType());
  68. Map<String, List<String>> requestQueryParams = context.getRequestQueryParams();
  69. if (requestQueryParams == null) {
  70. requestQueryParams = new HashMap<>();
  71. } else {
  72. requestQueryParams.remove(principalParamName);
  73. }
  74. if (!"anonymousUser".equalsIgnoreCase(currentPrincipalName)) {
  75. //将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去
  76. ArrayList<String> arrayList = new ArrayList<>();
  77. arrayList.add(currentPrincipalName);
  78. requestQueryParams.put(principalParamName, arrayList);
  79. context.setRequestQueryParams(requestQueryParams);
  80. }
  81. String contentType = request.getContentType();
  82. String body = null;
  83. try {
  84. body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
  85. } catch (IOException e) {
  86. e.printStackTrace();
  87. }
  88. body = bodyParamModify(body, currentPrincipalName, contentType);
  89. // context.set("requestEntity", new
  90. // ByteArrayInputStream(body.getBytes("UTF-8")));
  91. final byte[] reqBodyBytes = body.getBytes();
  92. context.setRequest(new HttpServletRequestWrapper(getCurrentContext().getRequest()) {
  93. @Override
  94. public ServletInputStream getInputStream() throws IOException {
  95. return new ServletInputStreamWrapper(reqBodyBytes);
  96. }
  97. @Override
  98. public int getContentLength() {
  99. return reqBodyBytes.length;
  100. }
  101. @Override
  102. public long getContentLengthLong() {
  103. return reqBodyBytes.length;
  104. }
  105. });
  106. return null;
  107. }
  108. private String bodyParamModify(String body, String principalName, String contentType) {
  109. log.info("原始 body : " + body);
  110. if (body == null) {
  111. return principalParamName + "=" + principalName;
  112. }
  113. if (contentType.contains("application/json")) {
  114. JSONObject json = JSON.parseObject(body);
  115. json.remove(principalParamName);
  116. json.put(principalParamName, principalName);
  117. body = json.toJSONString();
  118. } else if (contentType.contains("x-www-form-urlencoded")) {
  119. body = Arrays.stream(body.split("&")).filter(s -> !s.startsWith(principalParamName)).collect(Collectors.joining("&"));
  120. if (!StringUtils.equals(principalName, "anonymousUser")) {
  121. body += "&" + principalParamName + "=" + principalName;
  122. }
  123. }
  124. log.info("转换后的body : " + body);
  125. return body;
  126. }
  127. }