后端重构
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'dev-only-change-me-for-production';
|
||||
const JWT_ALGORITHM = 'HS256';
|
||||
const TOKEN_TTL_HOURS = 12;
|
||||
|
||||
function createAccessToken(user) {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const payload = {
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
is_super_admin: !!user.is_super_admin,
|
||||
iat: now,
|
||||
exp: now + TOKEN_TTL_HOURS * 3600,
|
||||
};
|
||||
return jwt.sign(payload, JWT_SECRET, { algorithm: JWT_ALGORITHM });
|
||||
}
|
||||
|
||||
function decodeToken(token) {
|
||||
return jwt.verify(token, JWT_SECRET, { algorithms: [JWT_ALGORITHM] });
|
||||
}
|
||||
|
||||
function getTokenTtlSeconds() {
|
||||
return TOKEN_TTL_HOURS * 3600;
|
||||
}
|
||||
|
||||
module.exports = { createAccessToken, decodeToken, getTokenTtlSeconds, TOKEN_TTL_HOURS };
|
||||
@@ -0,0 +1,35 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'dev-only-change-me-for-production';
|
||||
const JWT_ALGORITHM = 'HS256' as const;
|
||||
const TOKEN_TTL_HOURS = 12;
|
||||
|
||||
export interface JwtPayload {
|
||||
sub: number;
|
||||
username: string;
|
||||
is_super_admin: boolean;
|
||||
iat: number;
|
||||
exp: number;
|
||||
}
|
||||
|
||||
function createAccessToken(user: { id: number; username: string; is_super_admin?: boolean | number }): string {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const payload: JwtPayload = {
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
is_super_admin: !!user.is_super_admin,
|
||||
iat: now,
|
||||
exp: now + TOKEN_TTL_HOURS * 3600,
|
||||
};
|
||||
return jwt.sign(payload, JWT_SECRET, { algorithm: JWT_ALGORITHM });
|
||||
}
|
||||
|
||||
function decodeToken(token: string): JwtPayload {
|
||||
return jwt.verify(token, JWT_SECRET, { algorithms: [JWT_ALGORITHM] }) as unknown as JwtPayload;
|
||||
}
|
||||
|
||||
function getTokenTtlSeconds(): number {
|
||||
return TOKEN_TTL_HOURS * 3600;
|
||||
}
|
||||
|
||||
export { createAccessToken, decodeToken, getTokenTtlSeconds, TOKEN_TTL_HOURS };
|
||||
@@ -1,5 +1,5 @@
|
||||
const crypto = require('crypto');
|
||||
const { promisify } = require('util');
|
||||
import crypto from 'node:crypto';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
const pbkdf2Async = promisify(crypto.pbkdf2);
|
||||
|
||||
@@ -7,13 +7,13 @@ const ITERATIONS = 310000;
|
||||
const KEYLEN = 32;
|
||||
const DIGEST = 'sha256';
|
||||
|
||||
async function hashPassword(password) {
|
||||
async function hashPassword(password: string): Promise<string> {
|
||||
const salt = crypto.randomBytes(16).toString('hex');
|
||||
const hash = await pbkdf2Async(password, salt, ITERATIONS, KEYLEN, DIGEST);
|
||||
return `pbkdf2:${DIGEST}:${ITERATIONS}:${salt}:${hash.toString('hex')}`;
|
||||
}
|
||||
|
||||
async function verifyPassword(password, stored) {
|
||||
async function verifyPassword(password: string, stored: string): Promise<boolean> {
|
||||
if (!password || !stored || typeof stored !== 'string') return false;
|
||||
|
||||
const parts = stored.split(':');
|
||||
@@ -33,4 +33,4 @@ async function verifyPassword(password, stored) {
|
||||
return crypto.timingSafeEqual(expected, actual);
|
||||
}
|
||||
|
||||
module.exports = { hashPassword, verifyPassword };
|
||||
export { hashPassword, verifyPassword };
|
||||
@@ -1,24 +0,0 @@
|
||||
const ApiResponse = {
|
||||
success(data = null, msg = 'success') {
|
||||
return { code: 1, msg, data };
|
||||
},
|
||||
|
||||
error(msg = 'error', code = 0) {
|
||||
return { code, msg, data: null };
|
||||
},
|
||||
|
||||
noData(msg = 'no data') {
|
||||
return { code: 2, msg, data: null };
|
||||
},
|
||||
};
|
||||
|
||||
class PageData {
|
||||
constructor(items, total, skip, limit) {
|
||||
this.items = items;
|
||||
this.total = total;
|
||||
this.skip = skip;
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { ApiResponse, PageData };
|
||||
@@ -0,0 +1,28 @@
|
||||
export interface ApiResponseData<T = unknown> {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T | null;
|
||||
}
|
||||
|
||||
export const ApiResponse = {
|
||||
success<T>(data: T | null = null, msg = 'success'): ApiResponseData<T> {
|
||||
return { code: 1, msg, data };
|
||||
},
|
||||
|
||||
error(msg = 'error', code = 0): ApiResponseData<null> {
|
||||
return { code, msg, data: null };
|
||||
},
|
||||
|
||||
noData(msg = 'no data'): ApiResponseData<null> {
|
||||
return { code: 2, msg, data: null };
|
||||
},
|
||||
};
|
||||
|
||||
export class PageData<T> {
|
||||
constructor(
|
||||
public items: T[],
|
||||
public total: number,
|
||||
public skip: number,
|
||||
public limit: number
|
||||
) {}
|
||||
}
|
||||
Reference in New Issue
Block a user