You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

85 lines
2.2 KiB

import { eq } from "drizzle-orm";
import { dbGlobal } from "@/drizzle-pkg/lib/db";
import { users } from "@/drizzle-pkg/lib/schema/auth";
import type { IAuthStrategy, AuthUser } from "../../types/auth";
import {
verifyPassword,
isLocked,
} from "../lib/password";
import { signAccessToken } from "../lib/jwt";
export class PasswordStrategy implements IAuthStrategy {
readonly type = "password" as const;
async authenticate(credentials: {
email: string;
password: string;
ip?: string;
userAgent?: string;
}): Promise<AuthUser> {
const { email, password, ip, userAgent } = credentials;
const [user] = await dbGlobal
.select()
.from(users)
.where(eq(users.email, email))
.limit(1);
if (!user) {
throw { code: "INVALID_CREDENTIALS", message: "邮箱或密码错误" };
}
if (user.lockoutUntil && isLocked(user.lockoutUntil)) {
throw { code: "ACCOUNT_LOCKED", message: "账户已锁定,请稍后再试" };
}
const valid = await verifyPassword(password, user.password);
if (!valid) {
const attempts = (user.failedLoginAttempts || 0) + 1;
const lockoutUntil = attempts >= 5 ? new Date(Date.now() + 15 * 60_000) : null;
await dbGlobal
.update(users)
.set({
failedLoginAttempts: attempts,
lockoutUntil: lockoutUntil ?? null,
})
.where(eq(users.id, user.id));
throw { code: "INVALID_CREDENTIALS", message: "邮箱或密码错误" };
}
await dbGlobal
.update(users)
.set({
failedLoginAttempts: 0,
lockoutUntil: null,
lastLoginAt: new Date(),
lastLoginIp: ip ?? null,
})
.where(eq(users.id, user.id));
return {
id: user.id,
email: user.email,
username: user.username,
role: user.role,
status: user.status,
};
}
async generateTokens(
user: AuthUser,
sessionId: string
): Promise<{ accessToken: string; refreshToken: string }> {
const accessToken = await signAccessToken({
userId: user.id,
sessionId,
role: user.role,
});
return { accessToken, refreshToken: "" };
}
async revokeSession(sessionId: string): Promise<void> {
// delegated to AuthService
}
}