package cn.huge.gateway.filter;
|
|
import cn.huge.gateway.utils.JsonMapper;
|
import cn.huge.gateway.utils.ReturnBO;
|
import cn.huge.gateway.utils.SpringContextUtil;
|
import com.auth0.jwt.JWT;
|
import com.auth0.jwt.JWTVerifier;
|
import com.auth0.jwt.algorithms.Algorithm;
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Value;
|
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.DataBuffer;
|
import org.springframework.http.HttpStatus;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.CollectionUtils;
|
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.util.UriComponentsBuilder;
|
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Mono;
|
|
import java.io.UnsupportedEncodingException;
|
import java.net.URI;
|
import java.nio.charset.StandardCharsets;
|
import java.util.Arrays;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
/**
|
* @title: 网关拦截器
|
* @description: 网关拦截器
|
* @company: hugeinfo
|
* @author: liyj
|
* @time: 2021-11-05 16:51:48
|
* @version: 1.0.0
|
*/
|
@Slf4j
|
@Component
|
public class AuthFilter implements GlobalFilter, Ordered {
|
|
@Value("${jwt.secret-key}")
|
private String secretKey;
|
|
@Value("${jwt.iss-user}")
|
private String issUser;
|
|
@Value("${jwt.auth-skip-urls}")
|
private String[] skipAuthUrls;
|
|
@Value("${jwt.blacklist-key.format}")
|
private String jwtBlacklistKeyFormat;
|
|
@Override
|
public int getOrder() {
|
return -100;
|
}
|
|
/**
|
* 拦截方法
|
* @param exchange
|
* @param chain
|
* @return
|
*/
|
@Override
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
String url = exchange.getRequest().getURI().getPath();
|
//跳过不需要验证的路径
|
List<String> skipAuthUrlList = Arrays.asList(skipAuthUrls);
|
Boolean status = false;
|
if (!CollectionUtils.isEmpty(skipAuthUrlList)) {
|
for (String skipAuthUrl : skipAuthUrlList) {
|
if (url.indexOf(skipAuthUrl) != -1) {
|
status = true;
|
break;
|
}
|
}
|
}
|
if (status) {
|
return chain.filter(exchange);
|
} else {
|
JsonMapper jsonMapper = new JsonMapper();
|
ReturnBO returnBO = new ReturnBO();
|
//从请求头中取出token
|
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
|
//未携带token或token在黑名单内
|
if (StringUtils.isEmpty(token) || isBlackToken(token)) {
|
ServerHttpResponse originalResponse = exchange.getResponse();
|
originalResponse.setStatusCode(HttpStatus.OK);
|
originalResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
returnBO.setCode(401);
|
returnBO.setMsg("您尚未登录,请登录后重试!");
|
byte[] response = jsonMapper.toJson(returnBO).getBytes(StandardCharsets.UTF_8);
|
DataBuffer buffer = originalResponse.bufferFactory().wrap(response);
|
return originalResponse.writeWith(Flux.just(buffer));
|
} else {
|
//取出token包含的身份
|
returnBO = verifyJWT(token);
|
if (returnBO.getCode() != 0) {
|
ServerHttpResponse originalResponse = exchange.getResponse();
|
originalResponse.setStatusCode(HttpStatus.OK);
|
originalResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
byte[] response = jsonMapper.toJson(returnBO).getBytes(StandardCharsets.UTF_8);
|
DataBuffer buffer = originalResponse.bufferFactory().wrap(response);
|
return originalResponse.writeWith(Flux.just(buffer));
|
} else {
|
//将现在的request,添加当前身份
|
String userId = (String) returnBO.getData();
|
ServerHttpRequest mutableReq = null;
|
exchange.getRequest().mutate().header("Authorization-userId", userId).build();
|
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
|
return chain.filter(mutableExchange);
|
}
|
}
|
}
|
}
|
|
/**
|
* JWT验证
|
* @param token 授权信息
|
* @return Map
|
*/
|
private ReturnBO verifyJWT(String token){
|
ReturnBO returnBO = new ReturnBO();
|
try {
|
Algorithm algorithm = Algorithm.HMAC256(secretKey);
|
JWTVerifier verifier = JWT.require(algorithm)
|
.withIssuer(issUser)
|
.build();
|
DecodedJWT jwt = verifier.verify(token);
|
String userId = jwt.getClaim("userId").asString();
|
if (userId.isEmpty()){
|
returnBO.setCode(401);
|
returnBO.setMsg("您尚未登录,请登录后重试!");
|
}else{
|
returnBO.setCode(0);
|
returnBO.setData(userId);
|
}
|
} catch (JWTVerificationException e){
|
log.error("AuthFilter方法[verifyJWT]调用异常:"+e, e);
|
if (e.getMessage().indexOf("The Token has expired") != -1){
|
returnBO.setCode(401);
|
returnBO.setMsg("您尚未登录,请登录后重试!");
|
}else{
|
returnBO.setCode(401);
|
returnBO.setMsg("您尚未登录,请登录后重试!");
|
}
|
}
|
return returnBO;
|
}
|
|
/**
|
* 判断token是否在黑名单内
|
* @param token 授权信息
|
* @return boolean
|
*/
|
private boolean isBlackToken(String token){
|
assert token != null;
|
// return stringRedisTemplate.hasKey(String.format(jwtBlacklistKeyFormat, token));
|
return false;
|
}
|
|
/**
|
* usi追加custId
|
* @param uri uri
|
* @param custId custId参数
|
* @return
|
* @throws UnsupportedEncodingException
|
*/
|
private URI assembleUri(URI uri, String custId) {
|
StringBuilder query = new StringBuilder();
|
//追加custId参数
|
if(query.length() != 0){
|
query.append("&");
|
}
|
query.append("custId=");
|
query.append(custId);
|
//转码,生成新的URI
|
URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query.toString()).build(true).toUri();
|
return newUri;
|
}
|
}
|
/**
|
* -------------------_ooOoo_-------------------
|
* ------------------o8888888o------------------
|
* ------------------88" . "88------------------
|
* ------------------(| -_- |)------------------
|
* ------------------O\ = /O------------------
|
* ---------------____/`---'\____---------------
|
* -------------.' \\| |// `.-------------
|
* ------------/ \\||| : |||// \------------
|
* -----------/ _||||| -:- |||||- \-----------
|
* -----------| | \\\ - /// | |-----------
|
* -----------| \_| ''\---/'' | |-----------
|
* -----------\ .-\__ `-` ___/-. /-----------
|
* ---------___`. .' /--.--\ `. . __----------
|
* ------."" '< `.___\_<|>_/___.' >'"".-------
|
* -----| | : `- \`.;`\ _ /`;.`/ - ` : | |-----
|
* -----\ \ `-. \_ __\ /__ _/ .-` / /-----
|
* ======`-.____`-.___\_____/___.-`____.-'======
|
* -------------------`=---='
|
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
* ---------佛祖保佑---hugeinfo---永无BUG----------
|
*/
|