网关问题
This commit is contained in:
396
docs/网关认证方案.md
Normal file
396
docs/网关认证方案.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# Gateway 认证方案说明
|
||||
|
||||
## 问题背景
|
||||
|
||||
在微服务架构中,如果同时使用 Gateway 和 common-auth 模块,会出现**重复认证**的问题:
|
||||
|
||||
```
|
||||
浏览器 → Gateway (AuthGlobalFilter 验证 JWT)
|
||||
→ 微服务 (JwtAuthenticationFilter 再次验证 JWT) ❌ 重复!
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
|
||||
提供两种认证模式,通过配置选择:
|
||||
|
||||
### **模式一:Gateway 统一认证(推荐)**
|
||||
|
||||
Gateway 负责认证,微服务信任 Gateway 传递的用户信息。
|
||||
|
||||
#### 架构流程
|
||||
|
||||
```
|
||||
浏览器
|
||||
↓ (带 JWT Token)
|
||||
Nginx (80端口)
|
||||
↓
|
||||
Gateway (8080端口)
|
||||
├─ AuthGlobalFilter: 验证 JWT ✓
|
||||
├─ 提取用户信息 (userId, username)
|
||||
├─ 添加到请求头传递给下游
|
||||
└─ 路由到微服务
|
||||
↓
|
||||
微服务
|
||||
└─ GatewayTrustFilter: 从请求头获取用户信息 ✓
|
||||
```
|
||||
|
||||
#### 配置方式
|
||||
|
||||
**1. Gateway 服务配置** (`gateway/application.yml`)
|
||||
```yaml
|
||||
auth:
|
||||
enabled: true
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
auth-paths:
|
||||
- /auth/login
|
||||
- /auth/logout
|
||||
whitelist:
|
||||
- /actuator/**
|
||||
- /v3/api-docs/**
|
||||
```
|
||||
|
||||
**2. 微服务配置** (`system/application.yml`, `log/application.yml` 等)
|
||||
```yaml
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true # 关键:启用 Gateway 模式
|
||||
```
|
||||
|
||||
#### 优点
|
||||
- ✅ 避免重复认证,性能更好
|
||||
- ✅ 统一认证逻辑,易维护
|
||||
- ✅ 微服务之间调用不需要传递 JWT
|
||||
|
||||
---
|
||||
|
||||
### **模式二:微服务独立认证**
|
||||
|
||||
每个微服务独立验证 JWT,Gateway 不做认证。
|
||||
|
||||
#### 架构流程
|
||||
|
||||
```
|
||||
浏览器
|
||||
↓ (带 JWT Token)
|
||||
Nginx
|
||||
↓
|
||||
Gateway
|
||||
└─ 直接路由(不验证)
|
||||
↓
|
||||
微服务
|
||||
└─ JwtAuthenticationFilter: 验证 JWT ✓
|
||||
```
|
||||
|
||||
#### 配置方式
|
||||
|
||||
**1. Gateway 服务配置**
|
||||
```yaml
|
||||
auth:
|
||||
enabled: false # 关键:关闭 Gateway 认证
|
||||
```
|
||||
|
||||
**2. 微服务配置**
|
||||
```yaml
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: false # 或不配置(默认 false)
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
```
|
||||
|
||||
#### 适用场景
|
||||
- 微服务需要直接对外暴露(不经过 Gateway)
|
||||
- 对安全性要求极高,需要每层都验证
|
||||
|
||||
---
|
||||
|
||||
## 配置文件对比
|
||||
|
||||
### Gateway 服务 (`gateway/application.yml`)
|
||||
|
||||
```yaml
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: gateway-service
|
||||
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: auth-service
|
||||
uri: lb://auth-service
|
||||
predicates:
|
||||
- Path=/auth/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
- id: system-service
|
||||
uri: lb://system-service
|
||||
predicates:
|
||||
- Path=/system/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
# 认证配置
|
||||
auth:
|
||||
enabled: true # 是否启用认证
|
||||
gateway-mode: false # Gateway 本身不需要此配置
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
auth-paths:
|
||||
- /auth/login
|
||||
- /auth/logout
|
||||
- /auth/captcha
|
||||
- /auth/refresh
|
||||
whitelist:
|
||||
- /actuator/**
|
||||
- /v3/api-docs/**
|
||||
```
|
||||
|
||||
### 微服务配置 (Gateway 模式)
|
||||
|
||||
**auth-service/application.yml**
|
||||
```yaml
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: auth-service
|
||||
|
||||
# 认证配置
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true # 关键:信任 Gateway
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
whitelist:
|
||||
- /v3/api-docs/**
|
||||
- /actuator/**
|
||||
```
|
||||
|
||||
**system-service/application.yml**
|
||||
```yaml
|
||||
server:
|
||||
port: 8082
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: system-service
|
||||
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true # 关键:信任 Gateway
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工作原理
|
||||
|
||||
### Gateway 认证流程
|
||||
|
||||
**AuthGlobalFilter (Gateway 层)**
|
||||
```java
|
||||
1. 检查请求路径是否在白名单
|
||||
2. 提取 Authorization 请求头中的 JWT Token
|
||||
3. 验证 Token 是否过期
|
||||
4. 验证 Token 签名是否有效
|
||||
5. 提取用户信息 (userId, username)
|
||||
6. 将用户信息添加到请求头:
|
||||
- X-User-Id: {userId}
|
||||
- X-Username: {username}
|
||||
7. 路由到下游微服务
|
||||
```
|
||||
|
||||
### 微服务信任流程
|
||||
|
||||
**GatewayTrustFilter (微服务层)**
|
||||
```java
|
||||
1. 从请求头获取 Gateway 传递的用户信息:
|
||||
- X-User-Id
|
||||
- X-Username
|
||||
2. 构造 Spring Security 认证对象
|
||||
3. 设置到 SecurityContext
|
||||
4. 设置到 request attributes(供业务代码使用)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全考虑
|
||||
|
||||
### 内网安全
|
||||
|
||||
采用 Gateway 模式时,需确保:
|
||||
|
||||
1. **微服务不对外暴露**
|
||||
- 只能通过 Gateway 访问
|
||||
- 使用 Kubernetes Network Policy 或防火墙隔离
|
||||
|
||||
2. **请求头保护**
|
||||
- Gateway 在转发前清除任何客户端传递的 `X-User-Id` 等头
|
||||
- 防止伪造用户身份
|
||||
|
||||
3. **Gateway 过滤器增强**(可选)
|
||||
```java
|
||||
// 在 Gateway 中清除客户端可能伪造的请求头
|
||||
ServerHttpRequest mutatedRequest = request.mutate()
|
||||
.headers(headers -> {
|
||||
headers.remove("X-User-Id");
|
||||
headers.remove("X-Username");
|
||||
})
|
||||
.header(AuthContants.USER_ID_ATTRIBUTE, userId)
|
||||
.header(AuthContants.TOKEN_ATTRIBUTE, token)
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 测试 Gateway 模式
|
||||
|
||||
**1. 登录获取 Token**
|
||||
```bash
|
||||
curl -X POST http://localhost/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"admin","password":"123456"}'
|
||||
|
||||
# 响应
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"userId": "1001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**2. 使用 Token 访问受保护接口**
|
||||
```bash
|
||||
curl -X GET http://localhost/api/system/user/profile \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
**3. 查看日志验证单次认证**
|
||||
```
|
||||
Gateway 日志:
|
||||
[Gateway] Token 验证成功: userId=1001, path=/system/user/profile
|
||||
|
||||
System-Service 日志:
|
||||
[GatewayTrustFilter] 从 Gateway 获取用户信息: userId=1001, username=admin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从独立认证迁移到 Gateway 统一认证
|
||||
|
||||
**步骤 1**: 更新所有微服务配置
|
||||
```yaml
|
||||
auth:
|
||||
gateway-mode: true # 添加这一行
|
||||
```
|
||||
|
||||
**步骤 2**: 重启服务(先重启微服务,后重启 Gateway)
|
||||
```bash
|
||||
# 重启微服务
|
||||
docker-compose restart auth-service system-service log-service
|
||||
|
||||
# 重启 Gateway
|
||||
docker-compose restart gateway
|
||||
```
|
||||
|
||||
**步骤 3**: 验证功能
|
||||
- 测试登录
|
||||
- 测试受保护接口访问
|
||||
- 检查日志确认只认证一次
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: Gateway 模式下,微服务之间如何调用?
|
||||
|
||||
**A**: 微服务间调用不需要传递 JWT Token,直接调用即可。Gateway已经验证过身份。
|
||||
|
||||
```java
|
||||
// 微服务 A 调用微服务 B
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public void callServiceB() {
|
||||
// 直接调用,不需要添加 Authorization 头
|
||||
String result = restTemplate.getForObject(
|
||||
"http://service-b/api/xxx",
|
||||
String.class
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Q2: 如何获取当前登录用户信息?
|
||||
|
||||
**A**: 使用 `@HttpLogin` 注解或从 SecurityContext 获取。
|
||||
|
||||
```java
|
||||
// 方式一:使用注解(推荐)
|
||||
@GetMapping("/profile")
|
||||
public ResultDomain<UserDTO> getProfile(@HttpLogin LoginDomain loginDomain) {
|
||||
String userId = loginDomain.getUser().getUserId();
|
||||
// ...
|
||||
}
|
||||
|
||||
// 方式二:从 SecurityContext 获取
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
String userId = (String) auth.getPrincipal();
|
||||
```
|
||||
|
||||
### Q3: Gateway 模式更安全还是独立认证更安全?
|
||||
|
||||
**A**: 取决于网络拓扑:
|
||||
- **内网隔离良好**: Gateway 模式更优(性能好,维护简单)
|
||||
- **微服务直接对外**: 独立认证更安全(每层验证)
|
||||
|
||||
---
|
||||
|
||||
## 推荐配置
|
||||
|
||||
### 生产环境推荐
|
||||
|
||||
```yaml
|
||||
# Gateway
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: false
|
||||
|
||||
# 所有微服务
|
||||
auth:
|
||||
enabled: true
|
||||
gateway-mode: true
|
||||
```
|
||||
|
||||
### 开发环境(快速调试)
|
||||
|
||||
可以临时关闭认证:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
| 对比项 | Gateway 统一认证 | 微服务独立认证 |
|
||||
|--------|-----------------|---------------|
|
||||
| 认证次数 | 1次(仅 Gateway) | N次(每个服务) |
|
||||
| 性能 | ⭐⭐⭐⭐⭐ 最优 | ⭐⭐⭐ 一般 |
|
||||
| 维护性 | ⭐⭐⭐⭐⭐ 统一管理 | ⭐⭐⭐ 分散管理 |
|
||||
| 安全性 | ⭐⭐⭐⭐ 需内网隔离 | ⭐⭐⭐⭐⭐ 多层防护 |
|
||||
| 推荐场景 | 内网微服务架构 | 微服务对外暴露 |
|
||||
|
||||
**推荐使用 Gateway 统一认证模式!**
|
||||
Reference in New Issue
Block a user