网关登录校验
首先写一个demo
package com.hmall.gateway.filter;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.util.JwtTool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
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 java.util.List;
/**
* @Order(0) 和 实现Ordered接口一样
*/
@Slf4j
@Component
//@Order(0)
@RequiredArgsConstructor
public class AutoGlobalFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties;
private final JwtTool jwtTool;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1. 获取request对象
ServerHttpRequest request = exchange.getRequest();
//2. 判断是否需要拦截校验
if (isExclude(request.getPath().toString())) { //判断这个路径要不要拦截
//放行
return chain.filter(exchange);
}
//3. 获取请求头中 jwt令牌 Authorization
String authorization = request.getHeaders().getFirst("Authorization");
//4. 解析令牌 并校验
Long userId = null;
try {
userId = jwtTool.parseToken(authorization);
} catch (Exception e) {
log.error("解析令牌失败", e);
//设置响应状态码
ServerHttpResponse response = exchange.getResponse();
//401
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//5. 如果有效 将传递信息给后台
System.out.println("userId = " + userId);
String userIdStr = userId.toString();
ServerWebExchange swe = exchange.mutate()
.request(builder -> builder.header("user-info", userIdStr))
.build();
//6. 放行
return chain.filter(swe);
}
/**
* 校验方法
*
* @param path
* @return
*/
private boolean isExclude(String path) {
//获取排除的路径
List<String> excludePaths = authProperties.getExcludePaths();
for (String excludePath : excludePaths) {
//做校验
if (antPathMatcher.match(excludePath, path)) {
//匹配返回true
return true;
}
}
return false;
}
@Override
public int getOrder() {
return 0;
}
}
![登录校验的流程如图](https://i-blog.csdnimg.cn/direct/1bd1e33f5a374ea78130e838bdacefd4.png#pic_center)
AuthProperties实体类
package com.hmall.gateway.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Data
@Component
@ConfigurationProperties(prefix = "hm.auth")
public class AuthProperties {
private List<String> includePaths;
private List<String> excludePaths;
}
JwtTool 工具类 进行一系列的校验
package com.hmall.gateway.util;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.hmall.common.exception.UnauthorizedException;
import org.springframework.stereotype.Component;
import java.security.KeyPair;
import java.time.Duration;
import java.util.Date;
@Component
public class JwtTool {
private final JWTSigner jwtSigner;
public JwtTool(KeyPair keyPair) {
this.jwtSigner = JWTSignerUtil.createSigner("rs256", keyPair);
}
/**
* 创建 access-token
*
* @param userId 用户信息
* @return access-token
*/
public String createToken(Long userId, Duration ttl) {
// 1.生成jws
return JWT.create()
.setPayload("user", userId)
.setExpiresAt(new Date(System.currentTimeMillis() + ttl.toMillis()))
.setSigner(jwtSigner)
.sign();
}
/**
* 解析token
*
* @param token token
* @return 解析刷新token得到的用户信息
*/
public Long parseToken(String token) {
// 1.校验token是否为空
if (token == null) {
throw new UnauthorizedException("未登录");
}
// 2.校验并解析jwt
JWT jwt;
try {
jwt = JWT.of(token).setSigner(jwtSigner);
} catch (Exception e) {
throw new UnauthorizedException("无效的token", e);
}
// 2.校验jwt是否有效
if (!jwt.verify()) {
// 验证失败
throw new UnauthorizedException("无效的token");
}
// 3.校验是否过期
try {
JWTValidator.of(jwt).validateDate();
} catch (ValidateException e) {
throw new UnauthorizedException("token已经过期");
}
// 4.数据格式校验
Object userPayload = jwt.getPayload("user");
if (userPayload == null) {
// 数据为空
throw new UnauthorizedException("无效的token");
}
// 5.数据解析
try {
return Long.valueOf(userPayload.toString());
} catch (RuntimeException e) {
// 数据格式有误
throw new UnauthorizedException("无效的token");
}
}
}
登录校验过滤器 最后结果
package com.hmall.gateway.filter;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.util.JwtTool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
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 java.util.List;
/**
* @Order(0) 和 实现Ordered接口一样
*/
@Slf4j
@Component
//@Order(0)
@RequiredArgsConstructor
public class AutoGlobalFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties;
private final JwtTool jwtTool;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1. 获取request对象
ServerHttpRequest request = exchange.getRequest();
//2. 判断是否需要拦截校验
if (isExclude(request.getPath().toString())) { //判断这个路径要不要拦截
//放行
return chain.filter(exchange);
}
//3. 获取请求头中 jwt令牌 Authorization
String authorization = request.getHeaders().getFirst("Authorization");
//4. 解析令牌 并校验
Long userId = null;
try {
userId = jwtTool.parseToken(authorization);
} catch (Exception e) {
log.error("解析令牌失败", e);
//设置响应状态码
ServerHttpResponse response = exchange.getResponse();
//401
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//5. 如果有效 将传递信息给后台
System.out.println("userId = " + userId);
String userIdStr = userId.toString();
ServerWebExchange swe = exchange.mutate()
.request(builder -> builder.header("user-info", userIdStr))
.build();
//6. 放行
return chain.filter(swe);
}
/**
* 校验方法
*
* @param path
* @return
*/
private boolean isExclude(String path) {
//获取排除的路径
List<String> excludePaths = authProperties.getExcludePaths();
for (String excludePath : excludePaths) {
//做校验
if (antPathMatcher.match(excludePath, path)) {
//匹配返回true
return true;
}
}
return false;
}
@Override
public int getOrder() {
return 0;
}
}
注意点:
@RequiredArgsConstructor // 可以不用加@Autowired注解
private final AntPathMatcher antPathMatcher = new AntPathMatcher(); 需要new出来