持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
全局过滤器,做登录鉴权
- 如果是注册登录请求,去授权中心获取token
- 如果是其他请求,做 token 解析验证
- 如果是监控、swagger等请求,不需登录,直接放行
/**
*
*/
@AllArgsConstructor
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {
/**
* 注册中心客户端, 可以从注册中心中获取服务实例信息
*/
private final LoadBalancerClient loadBalancerClient;
private final RestTemplate restTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 直接放行,测试版
if (request.getURI().getPath().contains(GatewayConstant.LOGIN_URI)) {
return chain.filter(exchange);
}
// 1. 如果是登录
if (request.getURI().getPath().contains(GatewayConstant.LOGIN_URI)) {
// 去授权中心拿 token
String token = getTokenFromAuthorityCenter(
request, GatewayConstant.AUTHORITY_CENTER_TOKEN_URL_FORMAT
);
// header 中不能设置 null
response.getHeaders().add(
CommonConstant.JWT_USER_INFO_KEY,
null == token ? "null" : token
);
response.setStatusCode(HttpStatus.OK);
return response.setComplete();
}
// 2. 如果是注册
if (request.getURI().getPath().contains(GatewayConstant.REGISTER_URI)) {
// 去授权中心拿 token: 先创建用户, 再返回 Token
String token = getTokenFromAuthorityCenter(
request, GatewayConstant.AUTHORITY_CENTER_REGISTER_URL_FORMAT
);
response.getHeaders().add(
CommonConstant.JWT_USER_INFO_KEY,
null == token ? "null" : token
);
response.setStatusCode(HttpStatus.OK);
return response.setComplete();
}
// 3. 访问其他的服务, 则鉴权, 校验是否能够从 Token 中解析出用户信息
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(CommonConstant.JWT_USER_INFO_KEY);
String dev = headers.getFirst("dev");
if (dev.equals("dev")){
return chain.filter(exchange);
}
LoginUserInfo loginUserInfo = null;
try {
loginUserInfo = TokenParseUtil.parseUserInfoFromToken(token);
} catch (Exception ex) {
log.error("parse user info from token error: [{}]", ex.getMessage(), ex);
}
// 获取不到登录用户信息, 返回 401
if (null == loginUserInfo) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 解析通过, 则放行
return chain.filter(exchange);
}
/**
* <h2>从授权中心获取 Token</h2>
*/
private String getTokenFromAuthorityCenter(ServerHttpRequest request, String uriFormat) {
// service id 就是服务名字, 负载均衡
ServiceInstance serviceInstance = loadBalancerClient.choose(
CommonConstant.AUTHORITY_CENTER_SERVICE_ID
);
log.info("Nacos Client Info: [{}], [{}], [{}]", serviceInstance.getServiceId(), serviceInstance.getInstanceId(), JSON.toJSONString(serviceInstance.getMetadata()));
String requestUrl = String.format(
uriFormat, serviceInstance.getHost(), serviceInstance.getPort()
);
String body = getBodyFromBuffer(request);
log.info("login request url and body: [{}], [{}]", requestUrl, body);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
JwtToken token = restTemplate.postForObject(
requestUrl,
new HttpEntity<>(body, headers),
JwtToken.class
);
if (null != token) {
return token.getToken();
}
return null;
}
private String getBodyFromBuffer(ServerHttpRequest request) {
// 获取请求体
Flux<DataBuffer> body = request.getBody();
AtomicReference<String> bodyRef = new AtomicReference<>();
// 订阅缓冲区去消费请求体中的数据
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
// 一定要使用 DataBufferUtils.release 释放掉, 否则, 会出现内存泄露
DataBufferUtils.release(buffer);
bodyRef.set(charBuffer.toString());
});
// 获取 request body
return bodyRef.get();
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 2;
}
}