springcloud gateway自定义全局过滤器

全局过滤器作为bean注册成功后,不需要进行配置,就可以直接生效。

全局过滤器的作用范围是对所有的请求。

package com.demo.gateway.filter;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson.JSON;
import com.ftsafe.common.utils.jwt.CheckResult;
import com.ftsafe.common.utils.jwt.JwtUtils;
import com.ftsafe.config.BlackListConfig;
import com.ftsafe.config.CacheConstants;
import com.ftsafe.config.IgnoreWhiteProperties;
import com.ftsafe.config.R;
import com.ftsafe.config.ServletUtils;
import com.ftsafe.config.StringUtils;

import reactor.core.publisher.Mono;

/**
 * 网关鉴权
 * 
 * @author ruoyi
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered
{
    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);    
    
    // 多次反向代理后会有多个ip值 的分割符
 	private final static String IP_UTILS_FLAG = ",";
 	// 未知IP
 	private final static String UNKNOWN = "unknown";
 	// 本地 IP
 	private final static String LOCALHOST_IP = "0:0:0:0:0:0:0:1";
 	private final static String LOCALHOST_IP1 = "127.0.0.1";
    
    // 排除过滤的 uri 地址,nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;
    
    @Autowired
    private BlackListConfig blackListConfig;
    
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
        ServerHttpRequest request = exchange.getRequest();		
		String url = request.getURI().getPath();
		
		String host = request.getURI().getHost();
		
		// 输出请求                
        HttpHeaders headers = request.getHeaders();        
        System.out.println("======header: " + headers.toString());                
        
        MultiValueMap<String, HttpCookie> cookies = request.getCookies();
        System.out.println("======cookies: " + cookies.toString());
        
        // 黑名单
        List<String> blacklist = blackListConfig.getBlacklist();
        
        if(StringUtils.matches(url, blacklist))
        {
        	return setUnauthorizedResponse(exchange, "禁止访问");
        }
        
       
        // 跳过不需要验证的路径
        if (StringUtils.matches(url, ignoreWhite.getWhites()))
        {
        	// 设置IP地址到文件请求头
        	if(StringUtils.isNotEmpty(clientIp))
        	{
        		 ServerHttpRequest addRemoteIpReq = request.mutate().header(CacheConstants.REMOTE_IPADDR, clientIp)
                         .build();
                 ServerWebExchange mutableExchange = exchange.mutate().request(addRemoteIpReq).build();
             	
             	return chain.filter(mutableExchange);
        	}
           
        }
        
        String token = getToken(request);
        if (StringUtils.isBlank(token))
        {
            return setUnauthorizedResponse(exchange, "令牌不能为空");
        }
        
        
        CheckResult validateJWT = JwtUtils.validateJWT(token);
        
        if(validateJWT != null && validateJWT.isSuccess() == false)
        {
        	log.error("令牌验证失败");
        	log.info(validateJWT.toString());
        	
        	return setUnauthorizedResponse(exchange, "令牌验证失败");        	
        }
                      
                
        String userid = "userid";
        String username = "username";
        
        // 设置用户信息到请求
        ServerHttpRequest mutableReq = request.mutate().header(CacheConstants.DETAILS_USER_ID, userid)
                .header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build();
        ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();

        return chain.filter(mutableExchange);
    }

    private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
    {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);

        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());

        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
        }));
    }


    /**
     * 获取请求token
     */
    private String getToken(ServerHttpRequest request)
    {
        String token = request.getHeaders().getFirst(CacheConstants.HEADER);
        if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
        {
            token = token.replace(CacheConstants.TOKEN_PREFIX, "");
        }
        return token;
    }

    @Override
    public int getOrder()
    {
        return -200;
    }    
    
}

全局过滤器,需要实现GlobalFilter接口,需要添加@Component注解。

利用全局过滤器,可以实现统一的鉴权处理,日志处理等。

上一篇:SpringCloud系列之自定义GatewayFilterFactory


下一篇:SpringCloud Gateway的组成结构