java - 如何在spring cloud api网关终止请求流并重定向到不同的URL路由路径
问题描述
我已经实现了以下微服务应用程序。
请求流。
ui Client(http://localhost:8080) ------> spring cloud gateway(http://localhost:8081) ------> 用户微服务(http://localhost:8602)(api端点=/api/v1/users/bulkUpload)
我正在通过 spring 云网关服务向用户微服务发送 Ajax 请求。Ajax 请求包含刷新令牌作为 cookie 值。
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "http://localhost:8081/api/v1/users/bulkUpload",
xhrFields: {
withCredentials: true
},
data: newData,
processData: false,
contentType: false,
crossDomain: false,
cache: false,
timeout: 600000,
success: function (data) {
......
}
但是如果刷新令牌在 Ajax 请求中不可用,我想在 API 网关级别终止请求,并且我想将用户重定向到 Ui 客户端注销页面(http://localhost:8080/Logout)。为此,我实现了一个弹簧云网关过滤器,如下所示。
@Component
public class AccessTokenCheckingGlobalFilterPre extends AbstractGatewayFilterFactory<AccessTokenCheckingGlobalFilterPre.Config> {
@Value("${security.oauth2.client.client-id}")
private String client_id;
@Value("${security.oauth2.client.client-secret}")
private String client_secret;
public AccessTokenCheckingGlobalFilterPre() {
super(AccessTokenCheckingGlobalFilterPre.Config.class);
}
@Override
public GatewayFilter apply(AccessTokenCheckingGlobalFilterPre.Config config) {
return (exchange, chain) -> {
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
if(route!=null && request.getPath().toString().contains("oauth/token")) {
return chain.filter(exchange.mutate().request(request).response(response).build());
}else {
MultiValueMap<String, HttpCookie> cookies = request.getCookies();
List<HttpCookie> accessTokenList = cookies.get("access_token");
List<HttpCookie> refreshTokenList = cookies.get("refresh_token");
HttpHeaders heraders = request.getHeaders();
String access_token="";
String refresh_token = "";
if(accessTokenList != null) {
access_token = accessTokenList.get(0).getValue();
}
if(refreshTokenList != null) {
refresh_token = refreshTokenList.get(0).getValue();
}
if(access_token.isEmpty() && !refresh_token.isEmpty()) {
RestTemplate restTemplate = new RestTemplate();
String credentials = client_id + ":" + client_secret;
String encodedCredentials = new String(Base64.encode(credentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.add("Authorization", "Basic " + encodedCredentials);
HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
String access_token_url = "http://localhost:8602/oauth/token";
access_token_url += "?grant_type=refresh_token";
access_token_url += "&refresh_token=" + refresh_token;
ResponseEntity<String> aouthResponse = restTemplate.exchange(access_token_url, HttpMethod.POST, requestEntity, String.class);
String responseJson = access_token = aouthResponse.getBody();
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(responseJson);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
String newRefreshToken = node.path("refresh_token").asText();
String newAccessToken = node.path("access_token").asText();
int expiresIn = Integer.parseInt(node.path("expires_in").asText());
int refreshTokenExpireTime = Integer.parseInt(node.path("refreshTokenExpires_In").asText());
ResponseCookie accessTokenCookie = ResponseCookie.from("access_token", newAccessToken)
.path("/")
.maxAge(expiresIn)
.build();
ResponseCookie refreshTokenCookie = ResponseCookie.from("refresh_token", newRefreshToken)
.path("/")
.maxAge(refreshTokenExpireTime)
.build();
response.addCookie(refreshTokenCookie);
response.addCookie(accessTokenCookie);
access_token = newAccessToken;
}else if(refresh_token.isEmpty()){
//request.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
//response.setComplete();
return chain.filter(exchange.mutate().request(request).response(response).build());
}
final String value = access_token;
request = request.mutate()
.headers(httpHeaders -> httpHeaders.add("Authorization", "Bearer " + value))
.build();
}
return chain.filter(exchange.mutate().request(request).response(response).build());
};
}
public static class Config {
}
}
已实现此逻辑以检查请求中是否存在刷新令牌。除非它正在重定向 Ui 客户端注销页面(http://localhost:8080/Logout)。
}else if(refresh_token.isEmpty()){
//request.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
//response.setComplete();
return chain.filter(exchange.mutate().request(request).response(response).build());
}
但是,API 网关级别没有发生请求终止,请求仍在转发到用户微服务。
如何在 apigateway 过滤器处终止请求流并重定向回 ui 客户端注销页面。
解决方案
代替
}else if(refresh_token.isEmpty()){
//request.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
//response.setComplete();
return chain.filter(exchange.mutate().request(request).response(response).build());
}
重定向用户,使用
}else if(refresh_token.isEmpty()){
response.setStatusCode(HttpStatus.FOUND); //302
response
.getHeaders()
.set("Location", "/logout");
return response.setComplete();
}
推荐阅读
- amazon-web-services - 有和没有自定义注册和登录的 AWS Cognito?
- angular - 遍历Angular Ionic中的数组
- macros - 为什么宏不起作用?
- mongodb - MongoDB对象数组,按一些简单条件计数并按对象键分组
- wordpress - 如何通过 ACF 属性查询 Wordpress API?
- xaml - 数据绑定 ItemsControl
- numpy - 管道中的自定义 sklearn 转换器为 cross_validate 抛出 IndexError 但在使用 GridSearchCV 时不会
- sql-server - 如何使用 Sql Server 命令?
- delphi - 如何在 Delphi VCL 中更改组件的焦点颜色
- node.js - robots-js + opencv 截图以灰度显示