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 filter(ServerWebExchange exchange, GatewayFilterChain chain) { String url = exchange.getRequest().getURI().getPath(); //跳过不需要验证的路径 List 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---------- */