forked from kidgrow-microservices-platform

zhaoxiaohao
2021-03-18 deb1110ca94cb0ac7bcdc51b4e8dd00407792a94
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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<br>
 *
 * @Description: Token过滤器<br>
 * @Project: <br>
 * @CreateDate: Created in 2020/2/12 11:33 <br>
 * @Author: <a href="4345453@kidgrow.com">liuke</a>
 */
 
@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);
    }
 
}