|
|
@@ -1,16 +1,30 @@
|
|
|
package com.inspur.smsb.gateway.filter;
|
|
|
|
|
|
+import com.alibaba.cola.dto.SingleResponse;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
import com.google.common.base.Strings;
|
|
|
+import com.inspur.smsb.gateway.dto.KeycloakUserDto;
|
|
|
+import com.inspur.smsb.gateway.utils.HttpClientUtil;
|
|
|
import com.nimbusds.jose.JWSObject;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
|
|
|
+import org.apache.commons.httpclient.methods.PostMethod;
|
|
|
+import org.apache.commons.httpclient.methods.RequestEntity;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
|
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
|
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
import org.springframework.web.server.ServerWebExchange;
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
import java.text.ParseException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Optional;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 过滤器,在请求头中解析 JWT 字段,并解析出 userId 回填
|
|
|
@@ -20,25 +34,93 @@ import java.text.ParseException;
|
|
|
@Slf4j
|
|
|
@Component
|
|
|
public class WebFluxUserRequestInfoFilter implements GlobalFilter {
|
|
|
+ @Value("${keycloak.auth-server-url}")
|
|
|
+ private String keyCloakServiceUrl;
|
|
|
+ @Value("${keycloak.realm}")
|
|
|
+ private String realm;
|
|
|
+ @Value("${keycloak.resource}")
|
|
|
+ private String clientId;
|
|
|
+ @Value("${keycloak.credentials.secret}")
|
|
|
+ private String clientSecret;
|
|
|
+ @Value("${keycloak.adminUserId}")
|
|
|
+ private String adminUserId;
|
|
|
+
|
|
|
@Override
|
|
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
- try {
|
|
|
- String token = exchange.getRequest().getHeaders().getFirst("Authorization");
|
|
|
- if (Strings.isNullOrEmpty(token)) {
|
|
|
- return chain.filter(exchange);
|
|
|
+ String wxAppletId = exchange.getRequest().getHeaders().getFirst("WxAppletId");
|
|
|
+ if (!Strings.isNullOrEmpty(wxAppletId)) {
|
|
|
+ // search for userid
|
|
|
+ String tokenUrl = keyCloakServiceUrl + "realms/" + realm + "/protocol/openid-connect/token";
|
|
|
+ String token = getToken(tokenUrl, clientId, clientSecret);
|
|
|
+ if (StringUtils.hasText(token)) {
|
|
|
+ String url = keyCloakServiceUrl + "admin/realms/" + realm + "/users";
|
|
|
+ List<KeycloakUserDto> list = queryUsers(url, token);
|
|
|
+ list = list.stream().filter(keycloakUserDto -> {
|
|
|
+ Map attributes = keycloakUserDto.getAttributes();
|
|
|
+ String openid = Optional.ofNullable(attributes.get("wechat-applet-openid")).orElse("").toString();
|
|
|
+ return StringUtils.hasText(openid) && openid.equals(wxAppletId);
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ if (!list.isEmpty()) {
|
|
|
+ String userId = list.get(0).getId();
|
|
|
+
|
|
|
+ ServerHttpRequest request = exchange.getRequest()
|
|
|
+ .mutate()
|
|
|
+ .header("userId", userId)
|
|
|
+ .build();
|
|
|
+ // 把新的 exchange 放回到过滤链
|
|
|
+ return chain.filter(exchange.mutate().request(request).build());
|
|
|
+ }
|
|
|
}
|
|
|
- String realToken = token.replace("Bearer ", "");
|
|
|
- JWSObject jwsObject = JWSObject.parse(realToken);
|
|
|
-
|
|
|
- ServerHttpRequest request = exchange.getRequest()
|
|
|
- .mutate()
|
|
|
- .header("userId", String.valueOf(jwsObject.getPayload().toJSONObject().get("sub")))
|
|
|
- .build();
|
|
|
- // 把新的 exchange 放回到过滤链
|
|
|
- return chain.filter(exchange.mutate().request(request).build());
|
|
|
- } catch (ParseException e) {
|
|
|
- log.error(e.getMessage(), e);
|
|
|
return chain.filter(exchange);
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ String token = exchange.getRequest().getHeaders().getFirst("Authorization");
|
|
|
+ if (Strings.isNullOrEmpty(token)) {
|
|
|
+ return chain.filter(exchange);
|
|
|
+ }
|
|
|
+ String realToken = token.replace("Bearer ", "");
|
|
|
+ JWSObject jwsObject = JWSObject.parse(realToken);
|
|
|
+
|
|
|
+ if (adminUserId.equals(String.valueOf(jwsObject.getPayload().toJSONObject().get("sub")))) {
|
|
|
+ //just skip this adapter
|
|
|
+ return chain.filter(exchange);
|
|
|
+ }
|
|
|
+
|
|
|
+ ServerHttpRequest request = exchange.getRequest()
|
|
|
+ .mutate()
|
|
|
+ .header("userId", String.valueOf(jwsObject.getPayload().toJSONObject().get("sub")))
|
|
|
+ .build();
|
|
|
+ // 把新的 exchange 放回到过滤链
|
|
|
+ return chain.filter(exchange.mutate().request(request).build());
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error(e.getMessage(), e);
|
|
|
+ return chain.filter(exchange);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public String getToken(String tokenUrl, String clientId, String clientSecret) {
|
|
|
+ try {
|
|
|
+ String content = "grant_type=client_credentials&client_id=" + clientId + "&client_secret=" + clientSecret;
|
|
|
+ log.info("tokenUrl:{},content:{}", tokenUrl, content);
|
|
|
+ Map<String, Object> result = HttpClientUtil.httpClientPost(tokenUrl, content, "content-type");
|
|
|
+ log.info("请求参数:" + result);
|
|
|
+ return (String) result.get("access_token");
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error("获取token失败!{}", e.getMessage());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<KeycloakUserDto> queryUsers(String url, String token) {
|
|
|
+ String userMap = HttpClientUtil.sendGet(url, "Bearer " + token);
|
|
|
+ KeycloakUserDto[] result = JSONObject.parseObject(userMap, KeycloakUserDto[].class);
|
|
|
+ List<KeycloakUserDto> userList = new ArrayList<>();
|
|
|
+ for (KeycloakUserDto dto : result) {
|
|
|
+ userList.add(dto);
|
|
|
}
|
|
|
+ return userList;
|
|
|
}
|
|
|
}
|