add user module

This commit is contained in:
liuyi 2025-06-22 14:27:15 +08:00
parent 040b0b71d5
commit 46253b3a4f
5 changed files with 148 additions and 6 deletions

View File

@ -12,8 +12,8 @@ export function defaultUserConfig(configure: Configure): UserConfig {
return { return {
hash: 10, hash: 10,
jwt: { jwt: {
token_expired: configure.env.get('USER_TOKEN_EXPIRED', (v) => toNumber(v), 1800), tokenExpired: configure.env.get('USER_TOKEN_EXPIRED', (v) => toNumber(v), 1800),
refresh_token_expired: configure.env.get( refreshTokenExpired: configure.env.get(
'USER_REFRESH_TOKEN_EXPIRED', 'USER_REFRESH_TOKEN_EXPIRED',
(v) => toNumber(v), (v) => toNumber(v),
3600 * 30, 3600 * 30,

View File

@ -13,7 +13,7 @@ export class AccessTokenEntity extends BaseToken {
* *
*/ */
@OneToOne(() => RefreshTokenEntity, (token) => token.accessToken, { cascade: true }) @OneToOne(() => RefreshTokenEntity, (token) => token.accessToken, { cascade: true })
refreshToken: string; refreshToken: RefreshTokenEntity;
/** /**
* *

View File

@ -15,7 +15,7 @@ export abstract class BaseToken extends BaseEntity {
@Column({ @Column({
comment: '令牌过期时间', comment: '令牌过期时间',
}) })
expired_at: Date; expiredAt: Date;
@CreateDateColumn({ @CreateDateColumn({
comment: '令牌创建时间', comment: '令牌创建时间',

View File

@ -0,0 +1,142 @@
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import dayjs from 'dayjs';
import { Configure } from '@/modules/config/configure';
import { getTime } from '@/modules/core/helpers/time';
import { getUserConfig } from '@/modules/user/config';
import { UserEntity } from '@/modules/user/entities/UserEntity';
import { AccessTokenEntity } from '@/modules/user/entities/access.token.entity';
import { RefreshTokenEntity } from '@/modules/user/entities/refresh.token.entity';
import { JwtConfig, JwtPayload } from '@/modules/user/types';
/**
*
*/
@Injectable()
export class TokenService {
constructor(
protected configure: Configure,
protected jwtService: JwtService,
) {}
/**
* accessToken刷新AccessToken与RefreshToken
* @param accessToken
* @param response
*/
async refreshToken(accessToken: AccessTokenEntity, response: Response) {
const { user, refreshToken } = accessToken;
if (refreshToken) {
const now = await getTime(this.configure);
if (now.isAfter(refreshToken.expiredAt)) {
return null;
}
const token = await this.generateAccessToken(user, now);
await accessToken.remove();
response.header('token', token.accessToken.value);
return token;
}
return null;
}
/**
* AccessToken并存入数据库
* Refresh也存入数据库
* @param user
* @param now
*/
async generateAccessToken(
user: UserEntity,
now: dayjs.Dayjs,
): Promise<{ accessToken: AccessTokenEntity; refreshToken: RefreshTokenEntity }> {
const config = await getUserConfig<JwtConfig>(this.configure, 'jwt');
const accessTokenPayload: JwtPayload = { sub: user.id, iat: now.unix() };
const signed = this.jwtService.sign(accessTokenPayload);
const accessToken = new AccessTokenEntity();
accessToken.value = signed;
accessToken.user = user;
accessToken.expiredAt = now.add(config.tokenExpired, 'second').toDate();
await accessToken.save();
const refreshToken = await this.generateRefreshToken(
accessToken,
await getTime(this.configure),
);
return { accessToken, refreshToken };
}
/**
* RefreshToken并存入数据库
* @param accessToken
* @param now
*/
async generateRefreshToken(
accessToken: AccessTokenEntity,
now: dayjs.Dayjs,
): Promise<RefreshTokenEntity> {
const config = await getUserConfig<JwtConfig>(this.configure, 'jwt');
const refreshTokenPayload = { uuid: uuid() };
const refreshToken = new RefreshTokenEntity();
refreshToken.value = this.jwtService.sign(
refreshTokenPayload,
this.configure.env.get('USER_REFRESH_TOKEN_EXPIRED', 'my-refresh-secret'),
);
refreshToken.expiredAt = now.add(config.refreshTokenExpired, 'second').toDate();
refreshToken.accessToken = accessToken;
await refreshToken.save();
return refreshToken;
}
/**
* accessToken是否存在
* @param value
*/
async checkAccessToken(value: string) {
return AccessTokenEntity.findOne({ where: { value }, relations: ['user', 'refreshToken'] });
}
/**
* AccessToken且自动移除关联的RefreshToken
* @param value
*/
async removeAccessToken(value: string) {
const accessToken = await AccessTokenEntity.findOne({ where: { value } });
if (accessToken) {
await accessToken.remove();
}
}
/**
* RefreshToken
* @param value
*/
async removeRefreshToken(value: string) {
const refreshToken = await RefreshTokenEntity.findOne({
where: { value },
relations: ['accessToken'],
});
if (refreshToken) {
if (refreshToken.accessToken) {
await refreshToken.accessToken.remove();
}
await refreshToken.remove();
}
}
/**
* Token是否正确,
* @param token
*/
async verifyAccessToken(token: AccessTokenEntity) {
const result = this.jwtService.verify(
token.value,
this.configure.env.get('USER_TOKEN_SECRET', 'my-access-secret'),
);
if (result) {
return token.user;
}
return null;
}
}

View File

@ -19,11 +19,11 @@ export interface JwtConfig {
/** /**
* token过期时间 * token过期时间
*/ */
token_expired: number; tokenExpired: number;
/** /**
* refresh token * refresh token
*/ */
refresh_token_expired: number; refreshTokenExpired: number;
} }
/** /**