package com.kidgrow.zuul.filter;
import cn.hutool.extra.servlet.ServletUtil;
import com.kidgrow.common.constant.BaseConstants;
import com.kidgrow.common.exception.BizException;
import com.kidgrow.common.model.ResultBody;
import com.kidgrow.common.utils.StrHelper;
import com.kidgrow.common.utils.StrPool;
import com.kidgrow.jwt.client.properties.AuthClientProperties;
import com.kidgrow.jwt.client.utils.JwtTokenClientUtils;
import com.kidgrow.jwt.utils.JwtUserInfo;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
/**
* 石家庄喜高科技有限责任公司 版权所有 © Copyright 2020
*
* @Description: Token过滤器
* @Project:
* @CreateDate: Created in 2020/2/12 11:33
* @Author: liuke
*/
@Slf4j
public class TokenFilter extends BaseFilter{
@Autowired
private AuthClientProperties authClientProperties;
@Autowired
private JwtTokenClientUtils jwtTokenClientUtils;
/**
* pre:可以在请求被路由之前调用
* route:在路由请求时候被调用
* post:在route和error过滤器之后被调用
* error:处理请求时发生错误时被调用
*
* @return
*/
@Override
public String filterType() {
// 前置过滤器
return PRE_TYPE;
}
/**
* filterOrder:通过int值来定义过滤器的执行顺序
*
* @return
*/
@Override
public int filterOrder() {
// 数字越大,优先级越低
/**
* 一定要在 {@link org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter} 过滤器之后执行,因为这个过滤器做了路由 而我们需要这个路由信息来鉴权
* 这个过滤器会将很多我们鉴权需要的信息放置在请求上下文中。故一定要在此过滤器之后执行
*/
return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1;
}
/**
* 返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。在上例中,我们直接返回true,所以该过滤器总是生效
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体逻辑。需要注意,这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,
* 不对其进行路由,然后通过ctx.setResponseStatusCode(200)设置了其返回的错误码
*
* @return
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String clientIP = ServletUtil.getClientIP(request);
log.info("clientIP={}", clientIP);
// 不进行拦截的地址
if (isIgnoreToken()) {
log.debug("access filter not execute");
return null;
}
//获取token, 解析,然后想信息放入 heade
//1, 获取token
String userToken = getTokenFromRequest(authClientProperties.getUser().getHeaderName(), request);
//2, 解析token
JwtUserInfo userInfo = null;
//添加测试环境的特殊token
if (isDev() && StrPool.TEST.equalsIgnoreCase(userToken)) {
userInfo = new JwtUserInfo(1L, "kidgrow", "喜高科技", 1L, 1L);
}
try {
if (!isIgnoreToken() && userInfo == null) {
userInfo = jwtTokenClientUtils.getUserInfo(userToken);
}
} catch (BizException e) {
errorResponse(e.getMessage(), e.getCode(), 200);
return null;
} catch (Exception e) {
errorResponse("验证token出错", ResultBody.failed().getCode(), 200);
return null;
}
//3, 将信息放入header
if (userInfo != null) {
addHeader(ctx, BaseConstants.JWT_KEY_ACCOUNT, userInfo.getAccount());
addHeader(ctx, BaseConstants.JWT_KEY_USER_ID, userInfo.getUserId());
addHeader(ctx, BaseConstants.JWT_KEY_NAME, userInfo.getName());
addHeader(ctx, BaseConstants.JWT_KEY_ORG_ID, userInfo.getOrgId());
addHeader(ctx, BaseConstants.JWT_KEY_STATION_ID, userInfo.getStationId());
}
log.info("userInfo={}", userInfo);
return null;
}
private void addHeader(RequestContext ctx, String name, Object value) {
if (StringUtils.isEmpty(value)) {
return;
}
String valueStr = value.toString();
String valueEncode = StrHelper.encode(valueStr);
ctx.addZuulRequestHeader(name, valueEncode);
}
}