# 前端安全升级接入指南

为了提高安全性，后端鉴权机制已升级为 **Token + Device Binding + Session Enforcement**。

**⚠️ 核心变更：所有身份验证相关的接口现在都强制要求携带 `device_id`。**

前端必须配合进行以下改动，否则接口将返回 `422 Unprocessable Entity` (参数缺失) 或 `401 Unauthorized` (设备不匹配)。

---

## 🛠️ 接口改造清单

请检查并修改以下所有接口的调用参数：

### 1. 登录接口 (Login)
*   **URL**: `/api/v1/auth/login`
*   **变更**: 新增必填字段 `device_id`。
*   **说明**: 之前的文档描述有误，登录接口**必须**传此参数，否则无法建立会话。

**修改后示例：**
```typescript
const loginData = {
  username: "user1",
  password: "pwd",
  device_id: getDeviceId() // ✅ 必传
};
```

### 2. 注册接口 (Register)
*   **URL**: `/api/v1/auth/register`
*   **变更**: 新增必填字段 `device_id`。
*   **说明**: 注册成功后会自动登录，因此必须绑定当前设备。

**修改后示例：**
```typescript
const registerData = {
  username: "user1",
  password: "pwd",
  confirm_password: "pwd",
  device_id: getDeviceId() // ✅ 必传
};
```

### 3. 登出接口 (Logout)
*   **URL**: `/api/v1/auth/logout`
*   **变更**: 新增必填字段 `device_id`。
*   **说明**: 用于精准注销当前设备的会话，而不影响用户在其他设备上的登录状态。

**修改后示例：**
```typescript
const logoutData = {
  username: "user1",
  device_id: getDeviceId() // ✅ 必传
};
```

### 4. 心跳保活接口 (Heartbeat)
*   **URL**: `/api/v1/auth/heartbeat`
*   **变更**: 新增必填字段 `device_id`。
*   **说明**: 用于维持当前设备 Session 的活跃状态。

**修改后示例：**
```typescript
const heartbeatData = {
  username: "user1",
  device_id: getDeviceId() // ✅ 必传
};
```

### 5. 许可证验证接口 (Verify)
*   **URL**: `/api/v1/auth/verify`
*   **变更**: 新增必填字段 `device_id`。
*   **说明**: 后端会校验 Token 中的设备 ID 是否与参数中的设备 ID 一致，且 Session 是否活跃。

**修改后示例：**
```typescript
const verifyData = {
  username: "user1",
  timestamp: Date.now(),
  device_id: getDeviceId() // ✅ 必传
};
```

---

## 🚨 统一错误处理 (Interceptor)

由于新的强校验机制，`401 Unauthorized` 可能会在任何接口出现（不仅仅是 Token 过期，也可能是被踢下线）。

前端拦截器需要统一处理 `401`，强制跳转到登录页。

**Axios 拦截器示例：**

```typescript
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response && error.response.status === 401) {
      // 1. 清除本地 Token
      localStorage.removeItem('access_token');
      
      // 2. 提示用户
      const msg = error.response.data.detail || '登录已失效，请重新登录';
      // Message.error(msg); // Arco Design / Element UI
      console.error(msg);
      
      // 3. 跳转登录页
      // 如果是 Shell 环境，跳转到 Shell 登录
      if (window.location.hash.indexOf('/login') === -1) {
         window.location.href = '/shell/index.html#/login';
      }
    }
    return Promise.reject(error);
  }
);
```

---

## 💡 关于 device_id 的说明

`device_id` 是用于标识客户端设备的唯一字符串。

*   **生成方式**：建议在应用启动时检查 `LocalStorage`，如果没有则生成一个 UUID 并存入；如果有则直接读取。
*   **作用**：用于区分不同的客户端实例，实现单设备登录限制（互踢功能）。
*   **持久化**：必须确保存储在浏览器/CEP 环境的持久化存储中（如 `localStorage`），避免刷新页面后变化。
