整理思路
由网关Zuul进行Token颁布由网关Zuul进行登录认证
拦截拦截的配置等可以用Mysql存储配置或者配置文件,只配置默认放开的路径即可拦截后把在zuul中的token,换成跟后台用户关联的Uid等整体分为2步
创建Pre类型ZuulFilter转换token,加入Request Header中下游业务服务接收转换的Uid
Pre Zuul Filter
过滤器类型 : FilterConstants.PRE_TYPE过滤器优先级:跟debug 一样 FilterConstants.DEBUG_FILTER_ORDER是否开启:可以获取path判断某些不过滤可以自定义增加请求参数或者请求头可以自定义不传递,直接返回的响应码和响应体可以根据import org.flix.zuul.filters.support.FilterConstants;
service-id
判断是否处理自定义header如果起始request中已有,会被zuul覆盖@Componentpublic class PreTokenFilter extends ZuulFilter {@Autowiredprivate RouteLocator routeLocator;private UrlPathHelper urlPathHelper = new UrlPathHelper();@Overridepublic String filterType() {// 过滤器类型return FilterConstants.PRE_TYPE;}@Overridepublic int filterOrder() {//过滤器优先级return FilterConstants.DEBUG_FILTER_ORDER;}@Overridepublic boolean shouldFilter() {// 过滤器是否启用RequestContext ctx = RequestContext.getCurrentContext();final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());Route route = this.routeLocator.getMatchingRoute(requestURI);if (route != null) {// roadnet-serviceString location = route.getLocation();if (StrUtil.equals(location, "roadnet-service")) {return true;}}return false;}@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest(); // 获取请求 HttpServletRequestString token = request.getHeader("token");if (StrUtil.isBlank(token)) {token = request.getParameter("token");}if (null == token || "".equals(token)) {ctx.setSendZuulResponse(false); // 直接返回,不向后传递了 ctx.getResponse().setContentType("application/json; charset=utf-8");ctx.setResponseStatusCode(401); // 返回 http code 401Dict dict = Dict.create().set("code", "101").set("msg", "兄弟裂开了,token is not found");ctx.setResponseBody(JSONUtil.toJsonPrettyStr(dict));}setExtRequestHeader(ctx);setExtRequestQueryParams(ctx);return null;}private void setExtRequestHeader(RequestContext ctx) {ctx.addZuulRequestHeader("deptId", "lakerDept");ctx.addZuulRequestHeader("userId", "laker");}private void setExtRequestQueryParams(RequestContext ctx) {//将转换后的数据放入请求参数中Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();if (requestQueryParams == null) {requestQueryParams = new HashMap<>();}//将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去ArrayList<String> paramsList = new ArrayList<>();paramsList.add("lakerDept");ArrayList<String> paramsList1 = new ArrayList<>();paramsList1.add("laker");requestQueryParams.put("deptId", paramsList);requestQueryParams.put("userId", paramsList1);ctx.setRequestQueryParams(requestQueryParams);}}
下游业务服务接收
@GetMapping("/info")public String info() {System.err.println("用户ID:" + request.getHeader("userId"));}
其内部可以使用Filter或者拦截器去验证所有请求以及存放标记当前会话的userid
public class HttpHeaderParamFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;httpResponse.setCharacterEncoding("UTF-8");httpResponse.setContentType("application/json; charset=utf-8");String uid = httpRequest.getHeader("uid");if(StrUtils.isNotBlank(uid)){RibbonFilterContextHolder.getCurrentContext().add("uid", uid);chain.doFilter(httpRequest, response); } else {throw new BusinessException("没登录玩个锤子");}}@Overridepublic void destroy() {}}