如何用 JWT + API 网关实现微服务权限控制?

用“幼儿园通行证系统”比喻理解 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. 背后做了哪些事情?

用“幼儿园通行证系统”比喻:

颁发通行证时

  1. 小明告诉园长自己的名字和密码(用户登录);
  2. 园长确认小明身份后,写一张通行证,上面写着小明能去手工区和阅读角(生成 JWT,包含权限信息);
  3. 园长在通行证上盖章(生成签名),防止伪造。

检查通行证时

  1. 小明来到幼儿园门口,出示通行证(客户端发送请求,携带 JWT);
  2. 门卫接过通行证,检查是否有盖章,并且章是否正确(验证签名);
  3. 门卫打开通行证,看看小明能去哪些区域(解析 JWT 中的权限信息);
  4. 如果小明要去手工区,门卫看通行证上写着可以去,就放行(权限匹配,放行请求);
  5. 如果小明要去厨房,门卫发现通行证上没有写可以去,就不让进(权限不足,拒绝请求)。
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 中的权限信息,决定是否允许用户访问特定资源。

通过这种方式,微服务系统可以安全、高效地管理用户权限,就像幼儿园通过通行证系统管理小朋友的活动区域一样!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值