|
@@ -3,7 +3,6 @@ package shop.alien.gateway.config;
|
|
|
import com.alibaba.cloud.commons.lang.StringUtils;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import io.jsonwebtoken.Claims;
|
|
|
import io.jsonwebtoken.ExpiredJwtException;
|
|
|
import lombok.Data;
|
|
@@ -12,10 +11,12 @@ 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.cloud.gateway.filter.NettyWriteResponseFilter;
|
|
|
import org.springframework.core.Ordered;
|
|
|
import org.springframework.core.io.buffer.DataBuffer;
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
+import org.springframework.http.HttpMethod;
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
-import org.springframework.http.MediaType;
|
|
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
import org.springframework.web.server.ServerWebExchange;
|
|
@@ -25,12 +26,14 @@ import shop.alien.entity.store.StoreUser;
|
|
|
import shop.alien.gateway.mapper.StoreUserMapper;
|
|
|
import shop.alien.util.common.JwtUtil;
|
|
|
|
|
|
-import javax.servlet.http.HttpServletRequest;
|
|
|
-import javax.servlet.http.HttpServletResponse;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.Map;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import static org.apache.commons.codec.language.bm.Languages.ANY;
|
|
|
|
|
|
/**
|
|
|
* Jwt过滤器
|
|
@@ -64,15 +67,17 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
|
|
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
String url = exchange.getRequest().getURI().getPath();
|
|
|
log.info("====================>path: " + url);
|
|
|
-// if (url.startsWith("second/") || url.startsWith("store/")) {
|
|
|
-// url = url.substring(url.indexOf("/"), url.length() + 1);
|
|
|
-// }
|
|
|
+
|
|
|
+ if (Objects.equals(exchange.getRequest().getMethod(), HttpMethod.OPTIONS)) {
|
|
|
+ return allowChain(exchange, chain);
|
|
|
+ }
|
|
|
+
|
|
|
//跳过不需要验证的路径
|
|
|
if (null != skipAuthUrls && Arrays.asList(skipAuthUrls).contains(url)) {
|
|
|
- return chain.filter(exchange);
|
|
|
+ return allowChain(exchange, chain);
|
|
|
}
|
|
|
- if (url.startsWith("/store/webjars") || url.startsWith("/second/webjars")) {
|
|
|
- return chain.filter(exchange);
|
|
|
+ if (url.startsWith("/alienStore/webjars") || url.startsWith("/alienSecond/webjars")) {
|
|
|
+ return allowChain(exchange, chain);
|
|
|
}
|
|
|
|
|
|
//获取token
|
|
@@ -84,6 +89,7 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
|
|
|
ServerHttpResponse resp = exchange.getResponse();
|
|
|
if (StringUtils.isBlank(token)) {
|
|
|
//没有token
|
|
|
+ log.error("没有token");
|
|
|
return authError(resp, "请登录");
|
|
|
} else {
|
|
|
//有token
|
|
@@ -97,7 +103,6 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
|
|
|
//区分
|
|
|
if ("web".equals(deviceType)) {
|
|
|
//管理端单设备登录
|
|
|
-// redisKey = deviceType + "_" + tokenInfo.getClaim("userName").asString();
|
|
|
//不限制
|
|
|
return chain.filter(exchange);
|
|
|
} else {
|
|
@@ -118,26 +123,52 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
|
|
|
}
|
|
|
|
|
|
map.put("success", false);
|
|
|
+ log.error("认证错误: {}", map.toJSONString());
|
|
|
|
|
|
- exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
|
|
- return exchange.getResponse()
|
|
|
- .writeWith(Mono.just(exchange.getResponse()
|
|
|
- .bufferFactory()
|
|
|
- .wrap(map.toJSONString().getBytes())));
|
|
|
+ return authError(resp, map.toJSONString());
|
|
|
}
|
|
|
return chain.filter(exchange);
|
|
|
} catch (ExpiredJwtException e) {
|
|
|
if (e.getMessage().contains("Allowed clock skew")) {
|
|
|
+ log.error("认证过期", e);
|
|
|
return authError(resp, "认证过期");
|
|
|
} else {
|
|
|
+ log.error("认证失败", e);
|
|
|
return authError(resp, "认证失败");
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
+ log.error("认证失败", e);
|
|
|
return authError(resp, "认证失败");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private Mono<Void> allowChain(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
+ return chain.filter(exchange).then(Mono.fromRunnable(() -> {
|
|
|
+ exchange.getResponse().getHeaders().entrySet().stream()
|
|
|
+ .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
|
|
|
+ .filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
|
+ || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)
|
|
|
+ || kv.getKey().equals(HttpHeaders.VARY)))
|
|
|
+ .forEach(kv ->
|
|
|
+ {
|
|
|
+ // Vary只需要去重即可
|
|
|
+ if (kv.getKey().equals(HttpHeaders.VARY))
|
|
|
+ kv.setValue(kv.getValue().stream().distinct().collect(Collectors.toList()));
|
|
|
+ else {
|
|
|
+ List<String> value = new ArrayList<>();
|
|
|
+ if (kv.getValue().contains(ANY)) { //如果包含*,则取*
|
|
|
+ value.add(ANY);
|
|
|
+ kv.setValue(value);
|
|
|
+ } else {
|
|
|
+ value.add(kv.getValue().get(0)); // 否则默认取第一个
|
|
|
+ kv.setValue(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 认证错误输出
|
|
|
*
|
|
@@ -152,14 +183,15 @@ public class JwtTokenFilter implements GlobalFilter, Ordered {
|
|
|
json.put("code", HttpStatus.UNAUTHORIZED.value());
|
|
|
json.put("msg", message);
|
|
|
json.put("data", "");
|
|
|
+
|
|
|
+ log.error("认证错误响应: {}", json.toJSONString());
|
|
|
+
|
|
|
DataBuffer buffer = resp.bufferFactory().wrap(json.toString().getBytes(StandardCharsets.UTF_8));
|
|
|
return resp.writeWith(Flux.just(buffer));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public int getOrder() {
|
|
|
- return -100;
|
|
|
+ return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-
|