Files
nebula/docs/AUTH_JWT.md
2026-03-10 16:26:48 +08:00

9.4 KiB
Raw Blame History

JWT 认证系统文档

🔐 认证架构

Nebula 项目使用 JWT (JSON Web Token) 认证系统,提供完整的用户认证和授权功能。

核心特性

  • JWT 双 Token 机制Access Token + Refresh Token
  • 密码加密存储bcrypt
  • 灵活的 Token 过期时间配置
  • 中间件保护路由
  • 角色权限支持user/admin
  • 用户注册和登录
  • 修改密码
  • Token 刷新

📝 API 端点

1. 用户注册

POST /api/auth/register
Content-Type: application/json

{
  "username": "testuser",
  "email": "test@example.com",
  "password": "password123"
}

响应:

{
  "code": 0,
  "message": "success",
  "data": {
    "user": {
      "id": "uuid",
      "username": "testuser",
      "email": "test@example.com",
      "role": "user",
      "createdAt": "2026-03-10T12:00:00Z",
      "updatedAt": "2026-03-10T12:00:00Z"
    },
    "tokens": {
      "access_token": "eyJhbGciOiJIUzI1NiIs...",
      "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
      "expires_in": 7200
    }
  }
}

2. 用户登录

POST /api/auth/login
Content-Type: application/json

{
  "username": "testuser",
  "password": "password123"
}

响应: 同注册响应

3. 刷新 Token

POST /api/auth/refresh
Content-Type: application/json

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}

响应:

{
  "code": 0,
  "message": "success",
  "data": {
    "access_token": "new_access_token",
    "refresh_token": "new_refresh_token",
    "expires_in": 7200
  }
}

4. 获取当前用户信息

GET /api/auth/profile
Authorization: Bearer <access_token>

响应:

{
  "code": 0,
  "message": "success",
  "data": {
    "id": "uuid",
    "username": "testuser",
    "email": "test@example.com",
    "role": "user",
    "createdAt": "2026-03-10T12:00:00Z",
    "updatedAt": "2026-03-10T12:00:00Z"
  }
}

5. 修改密码

POST /api/auth/change-password
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "old_password": "password123",
  "new_password": "newpassword456"
}

响应:

{
  "code": 0,
  "message": "password changed successfully"
}

🧪 PowerShell 测试示例

完整测试流程

# 1. 注册用户
$registerBody = @{
    username = "testuser"
    email = "test@example.com"
    password = "password123"
} | ConvertTo-Json

$registerResponse = Invoke-RestMethod -Uri "http://localhost:9050/api/auth/register" `
  -Method Post -Body $registerBody -ContentType "application/json"

Write-Host "✅ 注册成功!"
Write-Host "用户 ID: $($registerResponse.data.user.id)"
Write-Host "Access Token: $($registerResponse.data.tokens.access_token.Substring(0, 20))..."

# 保存 token
$accessToken = $registerResponse.data.tokens.access_token
$refreshToken = $registerResponse.data.tokens.refresh_token

# 2. 登录(测试)
$loginBody = @{
    username = "testuser"
    password = "password123"
} | ConvertTo-Json

$loginResponse = Invoke-RestMethod -Uri "http://localhost:9050/api/auth/login" `
  -Method Post -Body $loginBody -ContentType "application/json"

Write-Host "✅ 登录成功!"

# 3. 获取用户信息
$headers = @{
    Authorization = "Bearer $accessToken"
}

$profile = Invoke-RestMethod -Uri "http://localhost:9050/api/auth/profile" `
  -Method Get -Headers $headers

Write-Host "✅ 获取用户信息成功!"
Write-Host "用户名: $($profile.data.username)"
Write-Host "邮箱: $($profile.data.email)"

# 4. 创建应用(测试认证保护)
$appBody = @{
    id = "test-app"
    name = "测试应用"
    description = "需要认证才能创建"
} | ConvertTo-Json

$app = Invoke-RestMethod -Uri "http://localhost:9050/api/apps" `
  -Method Post -Body $appBody -ContentType "application/json" -Headers $headers

Write-Host "✅ 创建应用成功(认证有效)!"

# 5. 刷新 Token
Start-Sleep -Seconds 2
$refreshBody = @{
    refresh_token = $refreshToken
} | ConvertTo-Json

$newTokens = Invoke-RestMethod -Uri "http://localhost:9050/api/auth/refresh" `
  -Method Post -Body $refreshBody -ContentType "application/json"

Write-Host "✅ Token 刷新成功!"

# 6. 修改密码
$changePasswordBody = @{
    old_password = "password123"
    new_password = "newpassword456"
} | ConvertTo-Json

$changeResult = Invoke-RestMethod -Uri "http://localhost:9050/api/auth/change-password" `
  -Method Post -Body $changePasswordBody -ContentType "application/json" -Headers $headers

Write-Host "✅ 密码修改成功!"

# 7. 测试未认证访问(应该失败)
try {
    Invoke-RestMethod -Uri "http://localhost:9050/api/apps" -Method Get
} catch {
    Write-Host "❌ 未认证访问被拒绝(正确)"
}

🔧 配置

环境变量

# JWT 密钥(生产环境必须修改!)
JWT_SECRET=your-secret-key-change-in-production

# Access Token 过期时间(默认 2 小时)
JWT_ACCESS_TOKEN_DURATION=7200  # 秒
# 或者
JWT_ACCESS_TOKEN_DURATION=2h

# Refresh Token 过期时间(默认 7 天)
JWT_REFRESH_TOKEN_DURATION=604800  # 秒
# 或者
JWT_REFRESH_TOKEN_DURATION=168h

推荐配置

开发环境:

  • Access Token: 2 小时
  • Refresh Token: 7 天

生产环境:

  • Access Token: 15 分钟 - 1 小时
  • Refresh Token: 30 天
  • 强密钥256位以上

🛡️ 安全特性

1. 密码加密

// 使用 bcrypt 加密
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

// 验证密码
bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))

2. Token 验证

  • 签名验证
  • 过期时间检查
  • 算法验证HMAC-SHA256

3. 中间件保护

// 需要认证
authRequired.Use(auth.JWTMiddleware(jwtService))

// 需要管理员权限
adminRequired.Use(auth.JWTMiddleware(jwtService), auth.AdminMiddleware())

📊 路由保护状态

公开路由(无需认证)

方法 路径 说明
POST /api/auth/register 用户注册
POST /api/auth/login 用户登录
POST /api/auth/refresh 刷新 Token
GET /api/check-update 检查更新

需要认证的路由

方法 路径 说明
GET /api/auth/profile 获取用户信息
POST /api/auth/change-password 修改密码
GET/POST/PUT/DELETE /api/apps/* 应用管理
GET/POST/PUT/DELETE /api/releases/* 版本管理
GET/POST/PUT/DELETE /api/assets/* 资源管理

🔄 Token 刷新流程

Client                          Server
  |                               |
  |-------- Request API --------->| (Access Token)
  |<----- 401 Token Expired ------| ❌
  |                               |
  |--- Refresh Token Request ---->| (Refresh Token)
  |<--- New Access Token ---------|  ✅
  |                               |
  |-------- Request API --------->| (New Access Token)
  |<-------- Success -------------|  ✅

💡 客户端集成示例

JavaScript/TypeScript

class AuthService {
  private accessToken: string | null = null;
  private refreshToken: string | null = null;

  async login(username: string, password: string) {
    const response = await fetch('http://localhost:9050/api/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password })
    });
    
    const data = await response.json();
    if (data.code === 0) {
      this.accessToken = data.data.tokens.access_token;
      this.refreshToken = data.data.tokens.refresh_token;
      
      // 保存到 localStorage
      localStorage.setItem('access_token', this.accessToken);
      localStorage.setItem('refresh_token', this.refreshToken);
    }
    return data;
  }

  async request(url: string, options: RequestInit = {}) {
    options.headers = {
      ...options.headers,
      'Authorization': `Bearer ${this.accessToken}`
    };

    let response = await fetch(url, options);
    
    // Token 过期,尝试刷新
    if (response.status === 401) {
      await this.refresh();
      options.headers['Authorization'] = `Bearer ${this.accessToken}`;
      response = await fetch(url, options);
    }
    
    return response.json();
  }

  async refresh() {
    const response = await fetch('http://localhost:9050/api/auth/refresh', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refresh_token: this.refreshToken })
    });
    
    const data = await response.json();
    if (data.code === 0) {
      this.accessToken = data.data.access_token;
      this.refreshToken = data.data.refresh_token;
      localStorage.setItem('access_token', this.accessToken);
      localStorage.setItem('refresh_token', this.refreshToken);
    }
  }
}

🚀 扩展功能

未来可添加

  1. Token 黑名单:退出登录时将 token 加入黑名单
  2. 双因素认证2FA:增强安全性
  3. OAuth2 第三方登录:支持 GitHub、Google 等
  4. 权限细粒度控制:基于资源的权限管理
  5. 登录日志:记录登录历史和异常
  6. IP 白名单:限制访问来源
  7. 账号锁定:多次登录失败后锁定

测试验证

  1. 注册新用户
  2. 登录获取 token
  3. 使用 token 访问受保护的 API
  4. 刷新 token
  5. 修改密码
  6. 未认证访问被拒绝

完整的 JWT 认证系统已经实现并运行正常!🎉