网关 Spring Cloud Zuul 自定义过滤器认证转换 Token

整理思路

  • 由网关Zuul进行Token颁布
  • 由网关Zuul进行登录认证拦截
  • 拦截的配置等可以用Mysql存储配置或者配置文件,只配置默认放开的路径即可
  • 拦截后把在zuul中的token,换成跟后台用户关联的Uid等

整体分为2步

  • 创建Pre类型ZuulFilter转换token,加入Request Header中
  • 下游业务服务接收转换的Uid

Pre Zuul Filter

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

  • 过滤器类型 : FilterConstants.PRE_TYPE
  • 过滤器优先级:跟debug 一样 FilterConstants.DEBUG_FILTER_ORDER
  • 是否开启:可以获取path判断某些不过滤
  • 可以自定义增加请求参数或者请求头
  • 可以自定义不传递,直接返回的响应码和响应体
  • 可以根据 service-id 判断是否处理
  • 自定义header如果起始request中已有,会被zuul覆盖
@Component
public class PreTokenFilter extends ZuulFilter {
    @Autowired
    private RouteLocator routeLocator;

    private UrlPathHelper urlPathHelper = new UrlPathHelper();

    @Override
    public String filterType() { // 过滤器类型
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() { //过滤器优先级
        return FilterConstants.DEBUG_FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() { // 过滤器是否启用
        RequestContext ctx = RequestContext.getCurrentContext();
        final String requestURI = this.urlPathHelper
                .getPathWithinApplication(ctx.getRequest());
        Route route = this.routeLocator.getMatchingRoute(requestURI);
        if (route != null) {
            // roadnet-service
            String location = route.getLocation();
            if (StrUtil.equals(location, "roadnet-service")) {
                return true;
            }
        }

        return false;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest(); // 获取请求 HttpServletRequest
        String 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 401
            Dict 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 {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public 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("没登录玩个锤子");
        }

    }
    @Override
    public void destroy() {
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lakernote

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值