102 lines
3.2 KiB
TypeScript
102 lines
3.2 KiB
TypeScript
import type { Context, Next } from 'hono';
|
|
|
|
import { authConfig } from '@/config/auth';
|
|
import db from '@/lib/db/client';
|
|
import { Passport } from 'passport';
|
|
import { Strategy as JwtStrategy } from 'passport-jwt';
|
|
import { Strategy as LocalStrategy } from 'passport-local';
|
|
import { v7 } from 'uuid';
|
|
|
|
import type { AuthJwtPayload } from './type';
|
|
|
|
import { ValidateUser } from './service';
|
|
// pnpm install nodemailer --save @types/nodemailer
|
|
|
|
// 生成验证令牌的异步函数,接受邮箱作为参数并返回生成的验证令牌
|
|
export const generateVerificationToken = async (email: string) => {
|
|
const token = v7();
|
|
const expires = new Date(Date.now() + 1000 * 60 * 60 * 24); // 24 hours
|
|
const existingEmail = await getVerificationTokenByEmail(email);
|
|
if (existingEmail) {
|
|
await db.verificationToken.delete({ where: { id: existingEmail.id } });
|
|
}
|
|
const verificationToken = await db.verificationToken.create({
|
|
data: {
|
|
email,
|
|
token,
|
|
expires,
|
|
},
|
|
});
|
|
return verificationToken;
|
|
};
|
|
// 根据邮箱获取验证令牌的异步函数
|
|
export const getVerificationTokenByEmail = async (email: string) => {
|
|
try {
|
|
const token = await db.verificationToken.findFirst({ where: { email } });
|
|
return token;
|
|
} catch (e) {
|
|
console.log(e);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
export const passport = new Passport();
|
|
|
|
export const passportInitialize = () => async (c: Context, next: Next) => {
|
|
const handle = passport.initialize();
|
|
await new Promise((reslove) => {
|
|
handle(c.req.raw as any, (c.res as any).raw, reslove);
|
|
});
|
|
await next();
|
|
};
|
|
passport.use(
|
|
'local',
|
|
new LocalStrategy({ usernameField: 'credential' }, async (credential, password, done) => {
|
|
console.log(credential, password);
|
|
try {
|
|
const user = await ValidateUser(credential, password);
|
|
if (!user.success) {
|
|
done({ message: user.message, code: 401 });
|
|
} else {
|
|
done(null, user.user as any);
|
|
}
|
|
} catch (error) {
|
|
done(error);
|
|
}
|
|
}),
|
|
);
|
|
passport.use(
|
|
'jwt',
|
|
new JwtStrategy(
|
|
{
|
|
jwtFromRequest: (req: any) => {
|
|
const authHeader = req.headers.get('authorization');
|
|
return authHeader
|
|
? authHeader.startsWith('Bearer ')
|
|
? authHeader.substring(7)
|
|
: null
|
|
: null;
|
|
},
|
|
secretOrKey: authConfig.jwtSecret,
|
|
},
|
|
async (jwtPayload: AuthJwtPayload, done) => {
|
|
try {
|
|
return done(null, jwtPayload);
|
|
} catch (error) {
|
|
return done(error, false);
|
|
}
|
|
},
|
|
),
|
|
);
|
|
export const verifyJWT = async (c: Context) =>
|
|
new Promise((resolve) => {
|
|
passport.authenticate('jwt', { session: false }, (err: any, user: AuthJwtPayload) => {
|
|
if (err || !user) {
|
|
resolve(false);
|
|
return undefined;
|
|
}
|
|
c.set('user', user);
|
|
resolve(true);
|
|
})(c.req.raw, (c.res as any).raw);
|
|
});
|