Spring Cloud Gateway 实现登录校验:构建统一认证入口
一、为什么需要在网关层进行登录校验?
🔒 遇到的实际问题:
- 用户请求直接打到某个微服务,绕过了登录认证;
- 每个服务都实现登录校验,代码冗余、安全隐患大;
- 缺乏统一认证体系,权限边界模糊;
- 无法集中管理黑名单、权限控制等安全规则。
✅ 网关统一登录校验的优势:
优点 | 说明 |
---|---|
安全性高 | 所有请求必须经过网关,避免绕过 |
易于维护 | 登录校验逻辑集中处理 |
可扩展性强 | 支持多种认证方式,如 JWT、Session、OAuth2 |
支持 Token 鉴权 | JWT 无状态、跨服务使用 |
降低服务耦合度 | 各服务只关注业务逻辑,不再处理认证 |
二、实战演示:Gateway + JWT 登录拦截实现
🔐 推荐方案:JWT(JSON Web Token)
- 前端登录成功后,认证服务返回 JWT Token;
- Token 存储在前端本地(localStorage / cookie);
- 所有请求都在 Header 中携带 Token;
- 网关拦截并解析 Token,验证其合法性;
- 若合法则放行请求,否则返回 401 未授权。
1️⃣ 引入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2️⃣ JWT 工具类
public class JwtUtil {
private static final String SECRET = "MySecretKey";
public static Claims parseToken(String token) throws Exception {
return Jwts.parser()
.setSigningKey(SECRET.getBytes(StandardCharsets.UTF_8))
.parseClaimsJws(token)
.getBody();
}
public static boolean isExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
3️⃣ 编写网关登录过滤器(GlobalFilter)
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private static final List<String> whiteList = Arrays.asList(
"/login", "/register", "/actuator/**"
);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
// 白名单放行
if (whiteList.stream().anyMatch(path::startsWith)) {
return chain.filter(exchange);
}
// 获取 Authorization 头
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.hasText(token) && token.startsWith("Bearer ")) {
token = token.replace("Bearer ", "");
try {
Claims claims = JwtUtil.parseToken(token);
if (!JwtUtil.isExpired(claims)) {
// Token 有效,放行
return chain.filter(exchange);
}
} catch (Exception e) {
// Token 非法或异常
}
}
// 拦截并返回 401
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return -100; // 优先级高
}
}
4️⃣ 配置白名单和跨域支持(可选)
@Configuration
public class CorsGlobalConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
三、常见问题与处理建议
问题 | 解决方案 |
---|---|
前端跨域无法访问 Gateway 接口 | 配置 CORS |
Token 解析失败或过期 | 返回 401 并提示重新登录 |
微服务之间需要用户信息 | 可通过请求头传递用户ID、角色等信息 |
白名单路径过多 | 可集中配置在 application.yml 或配置中心 |