207 lines
6.0 KiB
JavaScript
207 lines
6.0 KiB
JavaScript
const pool = require('../config/database');
|
|
const crypto = require('crypto');
|
|
|
|
class OAuthToken {
|
|
// 生成授权码
|
|
static generateAuthCode() {
|
|
return crypto.randomBytes(32).toString('hex');
|
|
}
|
|
|
|
// 生成访问令牌
|
|
static generateAccessToken() {
|
|
return crypto.randomBytes(64).toString('hex');
|
|
}
|
|
|
|
// 生成刷新令牌
|
|
static generateRefreshToken() {
|
|
return crypto.randomBytes(64).toString('hex');
|
|
}
|
|
|
|
// 创建授权码
|
|
static async createAuthCode(authCodeData) {
|
|
const { code, clientId, userId, redirectUri, scopes } = authCodeData;
|
|
const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10分钟过期
|
|
|
|
const query = `
|
|
INSERT INTO oauth_auth_codes (code, client_id, user_id, redirect_uri, scopes, expires_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING *
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [code, clientId, userId, redirectUri, scopes, expiresAt]);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
console.error('创建授权码失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 验证授权码
|
|
static async validateAuthCode(code, clientId, redirectUri) {
|
|
const query = `
|
|
SELECT * FROM oauth_auth_codes
|
|
WHERE code = $1 AND client_id = $2 AND redirect_uri = $3 AND expires_at > NOW()
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [code, clientId, redirectUri]);
|
|
// console.log(result.rows[0]);
|
|
// console.log(code, clientId, redirectUri);
|
|
// // console.log();
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
console.error('验证授权码失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 删除授权码
|
|
static async deleteAuthCode(code) {
|
|
const query = 'DELETE FROM oauth_auth_codes WHERE code = $1';
|
|
try {
|
|
await pool.query(query, [code]);
|
|
} catch (error) {
|
|
console.error('删除授权码失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 创建访问令牌
|
|
static async createAccessToken(accessTokenData) {
|
|
const { token, clientId, userId, scopes } = accessTokenData;
|
|
const expiresAt = new Date(Date.now() + 60 * 60 * 1000); // 1小时过期
|
|
|
|
const query = `
|
|
INSERT INTO oauth_access_tokens (token, client_id, user_id, scopes, expires_at)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING *
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [token, clientId, userId, scopes, expiresAt]);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
console.error('创建访问令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 创建刷新令牌
|
|
static async createRefreshToken(refreshTokenData) {
|
|
const { token, accessTokenId, clientId, userId } = refreshTokenData;
|
|
const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30天过期
|
|
|
|
const query = `
|
|
INSERT INTO oauth_refresh_tokens (token, access_token_id, client_id, user_id, expires_at)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING *
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [token, accessTokenId, clientId, userId, expiresAt]);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
console.error('创建刷新令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 验证访问令牌
|
|
static async validateAccessToken(token) {
|
|
const query = `
|
|
SELECT oat.*, u.username, u.email
|
|
FROM oauth_access_tokens oat
|
|
JOIN users u ON oat.user_id = u.id
|
|
WHERE oat.token = $1 AND oat.expires_at > NOW()
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [token]);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
console.error('验证访问令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 撤销刷新令牌
|
|
static async revokeRefreshToken(token) {
|
|
const query = 'UPDATE oauth_refresh_tokens SET is_revoked = true WHERE token = $1';
|
|
try {
|
|
await pool.query(query, [token]);
|
|
} catch (error) {
|
|
console.error('撤销刷新令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 验证刷新令牌
|
|
static async validateRefreshToken(token, clientId) {
|
|
const query = `
|
|
SELECT rt.*, at.scopes
|
|
FROM oauth_refresh_tokens rt
|
|
JOIN oauth_access_tokens at ON rt.access_token_id = at.id
|
|
WHERE rt.token = $1 AND rt.client_id = $2 AND rt.is_revoked = false AND rt.expires_at > NOW()
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [token, clientId]);
|
|
return result.rows[0];
|
|
} catch (error) {
|
|
console.error('验证刷新令牌失败:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 撤销访问令牌
|
|
static async revokeAccessToken(token) {
|
|
const query = 'DELETE FROM oauth_access_tokens WHERE token = $1';
|
|
try {
|
|
const result = await pool.query(query, [token]);
|
|
return result.rowCount > 0;
|
|
} catch (error) {
|
|
console.error('撤销访问令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 清理过期令牌(改进版)
|
|
static async cleanupExpiredTokens() {
|
|
try {
|
|
// 清理过期的访问令牌
|
|
await pool.query('DELETE FROM oauth_access_tokens WHERE expires_at < NOW()');
|
|
|
|
// 清理过期的刷新令牌
|
|
await pool.query('DELETE FROM oauth_refresh_tokens WHERE expires_at < NOW()');
|
|
|
|
// 清理过期的授权码
|
|
await pool.query('DELETE FROM oauth_auth_codes WHERE expires_at < NOW()');
|
|
|
|
console.log('已清理过期令牌');
|
|
} catch (error) {
|
|
console.error('清理过期令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 获取用户的活跃令牌
|
|
static async getActiveTokensByUserId(userId) {
|
|
const query = `
|
|
SELECT oat.token, oat.client_id, oat.scopes, oat.expires_at, oc.name as client_name
|
|
FROM oauth_access_tokens oat
|
|
JOIN oauth_clients oc ON oat.client_id = oc.client_id
|
|
WHERE oat.user_id = $1 AND oat.expires_at > NOW()
|
|
`;
|
|
|
|
try {
|
|
const result = await pool.query(query, [userId]);
|
|
return result.rows;
|
|
} catch (error) {
|
|
console.error('获取用户活跃令牌失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = OAuthToken; |