全局过滤器作为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注解。
利用全局过滤器,可以实现统一的鉴权处理,日志处理等。