API 认证指南
本文档详细介绍如何进行 API 认证和授权。
🔐 认证方式
Bearer Token 认证
叶动文档中心 API 使用 Bearer Token 进行认证。您需要在每个请求的 Authorization 头中包含有效的 token。
Authorization: Bearer YOUR_API_TOKEN
获取 API Token
方式一:通过登录接口获取
async function login(email, password) {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password
})
});
const data = await response.json();
if (data.code === 200) {
// 保存 token
localStorage.setItem('api_token', data.data.token);
return data.data.token;
} else {
throw new Error(data.message);
}
}
方式二:在管理后台生成
- 登录管理后台
- 进入 "API 管理" 页面
- 点击 "生成新 Token"
- 复制生成的 Token
🔑 Token 管理
Token 存储
// 安全存储 Token
class TokenManager {
static setToken(token) {
// 生产环境建议使用更安全的存储方式
localStorage.setItem('api_token', token);
}
static getToken() {
return localStorage.getItem('api_token');
}
static removeToken() {
localStorage.removeItem('api_token');
}
static isTokenValid() {
const token = this.getToken();
if (!token) return false;
try {
// 解析 JWT token(如果使用 JWT)
const payload = JSON.parse(atob(token.split('.')[1]));
const now = Date.now() / 1000;
return payload.exp > now;
} catch (error) {
return false;
}
}
}
Token 刷新
async function refreshToken() {
const refreshToken = localStorage.getItem('refresh_token');
if (!refreshToken) {
throw new Error('No refresh token available');
}
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
refresh_token: refreshToken
})
});
const data = await response.json();
if (data.code === 200) {
TokenManager.setToken(data.data.access_token);
localStorage.setItem('refresh_token', data.data.refresh_token);
return data.data.access_token;
} else {
// 刷新失败,需要重新登录
TokenManager.removeToken();
localStorage.removeItem('refresh_token');
throw new Error('Token refresh failed');
}
}
🛡️ 权限控制
权限级别
权限级别 | 描述 | 可访问的接口 |
---|---|---|
admin | 管理员 | 所有接口 |
user | 普通用户 | 用户相关接口 |
readonly | 只读用户 | 仅查询接口 |
权限检查
class APIClient {
constructor(token) {
this.token = token;
this.userInfo = null;
}
async getUserInfo() {
if (!this.userInfo) {
const response = await this.request('/api/user/profile');
this.userInfo = response.data;
}
return this.userInfo;
}
async hasPermission(permission) {
const userInfo = await this.getUserInfo();
return userInfo.permissions.includes(permission);
}
async request(endpoint, options = {}) {
const headers = {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
...options.headers
};
const response = await fetch(endpoint, {
...options,
headers
});
if (response.status === 401) {
// Token 过期或无效
throw new AuthError('Authentication failed');
}
if (response.status === 403) {
// 权限不足
throw new PermissionError('Permission denied');
}
return response.json();
}
}
🔒 安全最佳实践
1. Token 安全
// ✅ 推荐:使用 HTTPS
const API_BASE_URL = 'https://api.example.com';
// ❌ 避免:在 URL 中传递 token
// https://api.example.com/users?token=xxx
// ✅ 推荐:在 Header 中传递
headers: {
'Authorization': 'Bearer ' + token
}
2. Token 过期处理
class AuthenticatedAPIClient {
async request(endpoint, options = {}) {
try {
return await this.makeRequest(endpoint, options);
} catch (error) {
if (error.status === 401) {
// 尝试刷新 token
try {
await this.refreshToken();
return await this.makeRequest(endpoint, options);
} catch (refreshError) {
// 刷新失败,跳转到登录页
this.redirectToLogin();
throw refreshError;
}
}
throw error;
}
}
redirectToLogin() {
window.location.href = '/login';
}
}
3. 请求拦截器
// 使用 Axios 拦截器示例
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.example.com'
});
// 请求拦截器
apiClient.interceptors.request.use(
config => {
const token = TokenManager.getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器
apiClient.interceptors.response.use(
response => {
return response;
},
async error => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
await refreshToken();
return apiClient(originalRequest);
} catch (refreshError) {
TokenManager.removeToken();
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
🧪 测试认证
测试 Token 有效性
async function testAuthentication() {
const token = TokenManager.getToken();
if (!token) {
console.log('❌ 没有找到 Token');
return false;
}
try {
const response = await fetch('/api/auth/verify', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
console.log('✅ Token 有效');
return true;
} else {
console.log('❌ Token 无效');
return false;
}
} catch (error) {
console.log('❌ 验证失败:', error.message);
return false;
}
}
模拟认证流程
// 完整的认证流程示例
async function authenticationFlow() {
try {
// 1. 检查现有 token
if (TokenManager.isTokenValid()) {
console.log('✅ 使用现有 Token');
return TokenManager.getToken();
}
// 2. 尝试刷新 token
try {
const newToken = await refreshToken();
console.log('✅ Token 刷新成功');
return newToken;
} catch (refreshError) {
console.log('⚠️ Token 刷新失败,需要重新登录');
}
// 3. 重新登录
const email = prompt('请输入邮箱:');
const password = prompt('请输入密码:');
const token = await login(email, password);
console.log('✅ 登录成功');
return token;
} catch (error) {
console.error('❌ 认证失败:', error.message);
throw error;
}
}
📋 常见问题
Q: Token 过期了怎么办?
A: 系统会自动尝试刷新 Token。如果刷新失败,需要重新登录。
Q: 如何检查 Token 是否有效?
A: 可以调用 /api/auth/verify
接口验证 Token 有效性。
Q: Token 丢失了怎么办?
A: 需要重新登录获取新的 Token,或者在管理后台重新生成。
Q: 可以同时使用多个 Token 吗?
A: 可以,但建议为不同的应用或环境使用不同的 Token。