|
|
@@ -0,0 +1,206 @@
|
|
|
+package com.sciradar.api_gateway.filter;
|
|
|
+
|
|
|
+import com.sciradar.api_gateway.config.ApiGatewayConfiguration;
|
|
|
+import com.sciradar.api_gateway.jwt.JwtTokenHelper;
|
|
|
+import com.sciradar.api_gateway.util.RedisCacheUtils;
|
|
|
+import com.sciradar.component.DefaultMessageSource;
|
|
|
+import com.sciradar.constant.Constants;
|
|
|
+import com.sciradar.support.R;
|
|
|
+import com.sciradar.support.entity.UserVO;
|
|
|
+import com.sciradar.util.JsonUtil;
|
|
|
+import io.jsonwebtoken.JwtBuilder;
|
|
|
+import io.jsonwebtoken.Jwts;
|
|
|
+import io.jsonwebtoken.SignatureAlgorithm;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
|
|
+import org.springframework.cloud.gateway.filter.GlobalFilter;
|
|
|
+import org.springframework.context.support.ResourceBundleMessageSource;
|
|
|
+import org.springframework.core.Ordered;
|
|
|
+import org.springframework.core.io.buffer.DataBuffer;
|
|
|
+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.AntPathMatcher;
|
|
|
+import org.springframework.web.server.ServerWebExchange;
|
|
|
+import reactor.core.publisher.Mono;
|
|
|
+
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+import javax.xml.bind.DatatypeConverter;
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.Key;
|
|
|
+import java.util.Calendar;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+import static com.sciradar.constant.Constants.HTTP_HEADER_FROM;
|
|
|
+import static com.sciradar.constant.Constants.HTTP_HEADER_USER_ID;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 过滤拦截器
|
|
|
+ **/
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+public class PreAdminTokenRequestFilter implements GlobalFilter, Ordered {
|
|
|
+
|
|
|
+ private final AntPathMatcher pathMatcher = new AntPathMatcher();
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisCacheUtils redisCacheUtils;
|
|
|
+
|
|
|
+ @Value("${jwt.header:Authorization}")
|
|
|
+ private String header;
|
|
|
+
|
|
|
+ private final List<String> ignores;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private JwtTokenHelper jwtTokenHelper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ResourceBundleMessageSource messageSource;
|
|
|
+
|
|
|
+ private DefaultMessageSource defaultMessageSource = new DefaultMessageSource();
|
|
|
+
|
|
|
+ ExecutorService exec = Executors.newFixedThreadPool(2);
|
|
|
+
|
|
|
+ public PreAdminTokenRequestFilter(ApiGatewayConfiguration configuration) {
|
|
|
+ this.ignores = configuration.getFilter().getIgnores();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
+ ServerHttpResponse response = exchange.getResponse();
|
|
|
+ ServerHttpRequest request = exchange.getRequest();
|
|
|
+
|
|
|
+ String uri = request.getURI().getPath();
|
|
|
+ log.info("send {} request to {}", request.getMethod(), uri);
|
|
|
+ // 过滤排除项
|
|
|
+ for (String path : ignores) {
|
|
|
+ if (pathMatcher.match(path, uri)) {
|
|
|
+ log.info("ignore auth for url {}", uri);
|
|
|
+ //向headers中放文件
|
|
|
+ String secretKey = redisCacheUtils.createToken(Constants.SECRET_KEY);
|
|
|
+ ServerHttpRequest host = request.mutate().header(Constants.SECRET_KEY, secretKey).build();
|
|
|
+ //将现在的request 变成 change对象
|
|
|
+ ServerWebExchange build = exchange.mutate().request(host).build();
|
|
|
+ return chain.filter(build);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("authentication verification");
|
|
|
+
|
|
|
+// response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
|
|
+
|
|
|
+ String token = request.getHeaders().getFirst(header);
|
|
|
+ if (token == null || token.trim().equals("")) {
|
|
|
+ token = request.getQueryParams().getFirst("token");
|
|
|
+ }
|
|
|
+
|
|
|
+ String json = JsonUtil.getJsonFromObject(i18nConverter(1002));
|
|
|
+ DataBuffer data = exchange.getResponse().bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
|
|
|
+ if (token == null || "".equals(token)) {
|
|
|
+ response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
|
|
+ return response.writeWith(Mono.just(data));
|
|
|
+ }
|
|
|
+
|
|
|
+ String key = "oauth_token:" + token;
|
|
|
+ if (!redisCacheUtils.hasKey(key)) {
|
|
|
+ response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
|
|
+ return response.writeWith(Mono.just(data));
|
|
|
+ }
|
|
|
+
|
|
|
+ //校验TOKEN
|
|
|
+ R<UserVO> result = jwtTokenHelper.checkToken(redisCacheUtils.opsForValueGet(key));
|
|
|
+ if (result == null || !Constants.DEFAULT_SUCCESS_STATUS.equals(result.getStatus()) || result.getData() == null) {
|
|
|
+ response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
|
|
+ return response.writeWith(Mono.just(data));
|
|
|
+ }
|
|
|
+
|
|
|
+ String userToken = generateUserToken(result.getData());
|
|
|
+ redisCacheUtils.opsForValueSet(key, userToken, Constants.JWTEXPIRATION * 2, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ String userInfo = JsonUtil.getJsonFromObject(result.getData());
|
|
|
+ String secretKey = redisCacheUtils.createToken(Constants.SECRET_KEY);
|
|
|
+ //向headers中放文件
|
|
|
+ ServerHttpRequest newRequest = null;
|
|
|
+ try {
|
|
|
+ newRequest = request.mutate()
|
|
|
+ .header(Constants.CURRENT_USER, URLEncoder.encode(userInfo, Constants.CHARSET_UTF8))
|
|
|
+ .header(Constants.SECRET_KEY, secretKey)
|
|
|
+ .header(HTTP_HEADER_USER_ID, ""+result.getData().getId())
|
|
|
+ .header(HTTP_HEADER_FROM, "PRO")
|
|
|
+ .build();
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ // 将现在的request 变成 change对象
|
|
|
+ ServerWebExchange build = null;
|
|
|
+ if (newRequest != null) {
|
|
|
+ build = exchange.mutate().request(newRequest).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ return chain.filter(build);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int getOrder() {
|
|
|
+ return -100;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static R<Object> i18nConverter(ServerHttpRequest request, ResourceBundleMessageSource messageSource, Integer status, String... args) {
|
|
|
+ String lang = !StringUtils.isEmpty(request.getHeaders().getFirst(HttpHeaders.ACCEPT_LANGUAGE)) ? request.getHeaders().getFirst(HttpHeaders.ACCEPT_LANGUAGE) : request.getQueryParams().getFirst("lang");
|
|
|
+ messageSource.addBasenames("default");
|
|
|
+ Locale locale = !StringUtils.isEmpty(lang) ? new Locale(lang) : Locale.getDefault();
|
|
|
+ String message = messageSource.getMessage(String.valueOf(status), args, locale);
|
|
|
+ return new R<>(status, message);
|
|
|
+ }
|
|
|
+
|
|
|
+ private R<Object> i18nConverter(Integer status, String... args) {
|
|
|
+ String message = defaultMessageSource.getMessage(status, args);
|
|
|
+ return new R<>(status, message);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成token
|
|
|
+ * @author tq
|
|
|
+ * @date 2021/12/10 23:37
|
|
|
+ * @param User
|
|
|
+ */
|
|
|
+ private String generateUserToken(UserVO User) {
|
|
|
+ SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
|
|
|
+
|
|
|
+ long nowMillis = System.currentTimeMillis();
|
|
|
+ Date now = new Date(nowMillis);
|
|
|
+ // 生成签名密钥
|
|
|
+ byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(Constants.JWTSECTET);
|
|
|
+ Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
|
|
|
+ // 添加构成JWT的参数
|
|
|
+
|
|
|
+ JwtBuilder builder = Jwts.builder().claim(Constants.CURRENT_USER, JsonUtil.getJsonFromObject(User))
|
|
|
+ .setIssuer(Constants.JWTISSUER)
|
|
|
+ .setAudience(User.getId().toString())
|
|
|
+ .setIssuedAt(now)
|
|
|
+ .signWith(signatureAlgorithm, signingKey);
|
|
|
+ // 添加Token过期时间
|
|
|
+ if (Constants.JWTEXPIRATION >= 0) {
|
|
|
+ Calendar calendar = Calendar.getInstance();
|
|
|
+ calendar.add(Calendar.SECOND, Constants.JWTEXPIRATION);
|
|
|
+ builder.setNotBefore(now).setExpiration(calendar.getTime());
|
|
|
+ }
|
|
|
+ // 生成JWT
|
|
|
+ return Constants.JWTPREFIX + builder.compact();
|
|
|
+ }
|
|
|
+}
|