用“幼儿园通行证系统”比喻理解 JWT + API 网关权限控制
1. 什么是 JWT + API 网关权限控制?
想象幼儿园的“通行证系统”:
-
传统方式:老师要记住每个小朋友能去哪些区域(如手工区、阅读角),每次都要检查。
-
JWT + 网关方式:
- 园长给每个小朋友发一张通行证(JWT),上面写着名字和能去的区域(权限);
- 小朋友进入幼儿园时,门卫检查通行证(API 网关验证 JWT);
- 如果通行证有效,门卫看上面写的权限,让小朋友去对应的区域(网关根据 JWT 权限控制访问)。
2. 一共包含哪些部分?
画一个“幼儿园通行证管理系统”示意图:
┌───────────────────────────┐
│ JWT+API网关权限系统 │
├───────────────────────────┤
│ 园长:认证服务 │
│ ├─ 颁发通行证(生成JWT) │
│ └─ 验证用户身份 │
│ │
│ 门卫:API网关 │
│ ├─ 检查通行证有效性 │
│ ├─ 解析权限信息 │
│ └─ 控制访问权限 │
│ │
│ 通行证:JWT │
│ ├─ 包含用户身份信息 │
│ ├─ 包含权限信息 │
│ └─ 签名防篡改 │
│ │
│ 活动室:微服务 │
│ └─ 只允许有对应权限的人进入│
└───────────────────────────┘
3. 代码演示:JWT + API 网关权限控制
下面是一个简化的实现:
<?php
// 1. JWT生成(园长颁发通行证)
// 文件名:app/Service/AuthService.php
class AuthService {
private $secretKey = '幼儿园通行证密钥'; // 只有园长知道的密钥
/**
* 登录并生成JWT(就像园长给小朋友发通行证)
*/
public function login($username, $password) {
// 验证用户名密码(简化处理)
if ($username === 'xiaoming' && $password === '123456') {
// 生成JWT
$payload = [
'userId' => 1,
'username' => 'xiaoming',
'permissions' => ['read_books', 'play_game'], // 小明的权限
'exp' => time() + 3600 // 有效期1小时
];
// 生成签名(就像在通行证上盖章)
$header = json_encode(['alg' => 'HS256', 'typ' => 'JWT']);
$encodedHeader = $this->base64UrlEncode($header);
$encodedPayload = $this->base64UrlEncode(json_encode($payload));
$signature = hash_hmac('sha256', "{$encodedHeader}.{$encodedPayload}", $this->secretKey, true);
$encodedSignature = $this->base64UrlEncode($signature);
// 返回JWT(通行证)
return "{$encodedHeader}.{$encodedPayload}.{$encodedSignature}";
}
return null;
}
private function base64UrlEncode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
}
// 2. API网关权限验证(门卫检查通行证)
// 文件名:app/Middleware/AuthMiddleware.php
class AuthMiddleware {
private $secretKey = '幼儿园通行证密钥'; // 和园长用的同一把密钥
public function process($request, $handler) {
// 从请求头中获取JWT(通行证)
$token = $request->getHeaderLine('Authorization');
// 检查是否有通行证
if (empty($token)) {
return response()->json(['message' => '请先登录'], 401);
}
// 验证JWT有效性(就像门卫检查通行证是否伪造)
$parts = explode('.', $token);
if (count($parts) !== 3) {
return response()->json(['message' => '无效的通行证'], 401);
}
list($encodedHeader, $encodedPayload, $encodedSignature) = $parts;
// 验证签名(就像检查通行证上的章是否正确)
$signature = $this->base64UrlDecode($encodedSignature);
$expectedSignature = hash_hmac(
'sha256',
"{$encodedHeader}.{$encodedPayload}",
$this->secretKey,
true
);
if ($signature !== $expectedSignature) {
return response()->json(['message' => '伪造的通行证'], 403);
}
// 解析JWT中的权限信息(就像门卫看通行证上写的权限)
$payload = json_decode($this->base64UrlDecode($encodedPayload), true);
// 检查是否有访问该接口的权限(就像检查小朋友是否能去某个活动室)
$requiredPermission = $this->getRequiredPermission($request);
if (!empty($requiredPermission) && !in_array($requiredPermission, $payload['permissions'])) {
return response()->json(['message' => '权限不足'], 403);
}
// 权限验证通过,放行请求(就像门卫让小朋友进入对应的活动室)
return $handler->handle($request);
}
private function getRequiredPermission($request) {
// 根据请求路径确定需要的权限(简化处理)
$path = $request->getUri()->getPath();
if (str_contains($path, '/books')) {
return 'read_books';
}
if (str_contains($path, '/games')) {
return 'play_game';
}
return null;
}
private function base64UrlDecode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}
}
// 3. 微服务接口(活动室)
// 文件名:app/Controller/BookController.php
class BookController {
/**
* 获取图书列表(需要'read_books'权限)
*/
public function index() {
return response()->json([
'books' => ['《小熊绘本》', '《小猪唏哩呼噜》', '《猜猜我有多爱你》']
]);
}
}
// 文件名:app/Controller/GameController.php
class GameController {
/**
* 玩游戏(需要'play_game'权限)
*/
public function play() {
return response()->json([
'message' => '开始玩游戏:丢手绢!'
]);
}
}
4. 背后做了哪些事情?
用“幼儿园通行证系统”比喻:
颁发通行证时:
- 小明告诉园长自己的名字和密码(用户登录);
- 园长确认小明身份后,写一张通行证,上面写着小明能去手工区和阅读角(生成 JWT,包含权限信息);
- 园长在通行证上盖章(生成签名),防止伪造。
检查通行证时:
- 小明来到幼儿园门口,出示通行证(客户端发送请求,携带 JWT);
- 门卫接过通行证,检查是否有盖章,并且章是否正确(验证签名);
- 门卫打开通行证,看看小明能去哪些区域(解析 JWT 中的权限信息);
- 如果小明要去手工区,门卫看通行证上写着可以去,就放行(权限匹配,放行请求);
- 如果小明要去厨房,门卫发现通行证上没有写可以去,就不让进(权限不足,拒绝请求)。
5. 使用场景
- 微服务权限控制:不同微服务需要不同权限才能访问;
- 单点登录(SSO):一个系统登录后,其他系统可以信任该用户身份;
- 前后端分离:前端通过 JWT 与后端交互,无需存储 session;
- 第三方集成:允许第三方应用通过 JWT 访问特定资源;
- 权限分级:不同角色(如管理员、普通用户)有不同权限。
思维导图:JWT + API 网关权限控制
┌───────────────────┐
│ JWT+API网关权限 │
│ (幼儿园通行证) │
├───────────────────┤
│ 核心组件: │
│ ├─ 认证服务 │
│ ├─ API网关 │
│ ├─ JWT令牌 │
│ └─ 微服务 │
│ │
│ 工作流程: │
│ 1. 用户登录 │
│ 2. 生成JWT │
│ 3. 请求携带JWT │
│ 4. 网关验证JWT │
│ 5. 检查权限 │
│ 6. 放行或拒绝 │
└───────────────────┘
流程图:JWT + API 网关权限流程
用户登录 → 认证服务验证身份 → 生成JWT → 客户端请求 → API网关 →
│ │ │
│ │ JWT无效 │ JWT有效
│ │ 返回401 │ ↓
│ │ │ 解析权限
│ │ │ ↓
│ │ │ 权限匹配?
│ │ │ ↓
│ │ 是 │ 否
│ │ ↓ │ ↓
│ └── 放行请求 ──→ 返回403
概念图:JWT + API 网关关系
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 用户登录 │───→│ 认证服务 │───→│ 生成JWT │
└─────────────┘ └─────────────┘ └─────────────┘
│ │
│ ↓
┌─────────────┐ ┌─────────┴────────┐ ┌─────────────┐
│ 客户端请求 │───→│ API网关 │───→│ 权限验证 │
└─────────────┘ └──────────────────┘ └─────────────┘
│ │
│ 权限不足 │ 权限通过
│ 返回403 │ ↓
│ │ ┌─────────────┐
│ └─→│ 微服务 │
│ └─────────────┘
总结:JWT + API 网关是微服务的“智能通行证系统”
- JWT:就像幼儿园的通行证,包含用户身份和权限信息,并且有防篡改的签名;
- API 网关:就像幼儿园的门卫,负责检查通行证的有效性和权限信息;
- 权限控制:根据 JWT 中的权限信息,决定是否允许用户访问特定资源。
通过这种方式,微服务系统可以安全、高效地管理用户权限,就像幼儿园通过通行证系统管理小朋友的活动区域一样!