GatewaySecurityFilter.java 3.9 KB
Newer Older
1
package com.youlai.gateway.filter;
2 3

import cn.hutool.core.util.StrUtil;
4 5
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
6
import com.nimbusds.jose.JWSObject;
.  
有来技术 已提交
7
import com.youlai.common.constant.SecurityConstants;
8
import com.youlai.common.result.ResultCode;
H
haoxr 已提交
9
import com.youlai.gateway.util.ResponseUtils;
10
import lombok.RequiredArgsConstructor;
11 12
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
H
haoxr 已提交
13
import org.apache.logging.log4j.util.Strings;
H
haoxr 已提交
14
import org.springframework.beans.factory.annotation.Value;
15 16 17
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
18
import org.springframework.data.redis.core.RedisTemplate;
19
import org.springframework.http.server.reactive.ServerHttpRequest;
20
import org.springframework.http.server.reactive.ServerHttpResponse;
21 22 23 24
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

25 26
import java.net.URLEncoder;

27
/**
28
 * 安全拦截全局过滤器
29 30
 * <p>
 * 善后一些无关紧要的工作,在 ResourceServerManager#check 鉴权之后执行
31
 *
有来技术 已提交
32
 * @author <a href="mailto:xianrui0365@163.com">haoxr</a>
33
 * @date 2022/2/15
34 35 36
 */
@Component
@Slf4j
37
@RequiredArgsConstructor
38
public class GatewaySecurityFilter implements GlobalFilter, Ordered {
H
haoxr 已提交
39

40 41 42 43
    private final RedisTemplate redisTemplate;

    @Value("${spring.profiles.active}")
    private String env;
H
haoxr 已提交
44

45 46 47
    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
H
haoxr 已提交
48 49 50 51

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

52
        // 线上环境请求拦截处理
53 54 55 56 57 58 59 60
        String requestPath = request.getPath().pathWithinApplication().value();
        if (env.equals("prod")) {
            String methodValue = request.getMethodValue();
            if (SecurityConstants.PROD_FORBID_METHODS.contains(methodValue)) { // PUT和DELETE方法禁止
                if (!SecurityConstants.PROD_PERMIT_PATHS.contains(requestPath)) { // PUT和DELETE方法需要放行的方法
                    return ResponseUtils.writeErrorInfo(response, ResultCode.FORBIDDEN_OPERATION);
                }
            } else {
61
                if (SecurityConstants.PROD_FORBID_PATHS.contains(requestPath)) { // POST等放行的方法禁止特殊的请求路径
62 63 64
                    return ResponseUtils.writeErrorInfo(response, ResultCode.FORBIDDEN_OPERATION);
                }
            }
H
haoxr 已提交
65 66
        }

67
        // 非JWT放行不做后续解析处理
.  
有来技术 已提交
68
        String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_KEY);
69
        if (StrUtil.isBlank(token) || !StrUtil.startWithIgnoreCase(token, SecurityConstants.JWT_PREFIX)) {
70 71
            return chain.filter(exchange);
        }
H
haoxr 已提交
72

有来技术 已提交
73
        // 解析JWT获取jti,以jti为key判断redis的黑名单列表是否存在,存在则拦截访问
.  
有来技术 已提交
74
        token = StrUtil.replaceIgnoreCase(token, SecurityConstants.JWT_PREFIX, Strings.EMPTY);
75
        String payload = StrUtil.toString(JWSObject.parse(token).getPayload());
76
        JSONObject jsonObject = JSONUtil.parseObj(payload);
.  
有来技术 已提交
77 78
        String jti = jsonObject.getStr(SecurityConstants.JWT_JTI);
        Boolean isBlack = redisTemplate.hasKey(SecurityConstants.TOKEN_BLACKLIST_PREFIX + jti);
79
        if (isBlack) {
H
haoxr 已提交
80
            return ResponseUtils.writeErrorInfo(response, ResultCode.TOKEN_ACCESS_FORBIDDEN);
81 82
        }

H
haoxr 已提交
83 84
        // 存在token且不是黑名单,request写入JWT的载体信息
        request = exchange.getRequest().mutate()
.  
有来技术 已提交
85
                .header(SecurityConstants.JWT_PAYLOAD_KEY, URLEncoder.encode(payload, "UTF-8"))
H
haoxr 已提交
86
                .build();
87 88 89 90 91 92 93 94 95
        exchange = exchange.mutate().request(request).build();
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}