add user module
This commit is contained in:
parent
040b0b71d5
commit
46253b3a4f
@ -12,8 +12,8 @@ export function defaultUserConfig(configure: Configure): UserConfig {
|
||||
return {
|
||||
hash: 10,
|
||||
jwt: {
|
||||
token_expired: configure.env.get('USER_TOKEN_EXPIRED', (v) => toNumber(v), 1800),
|
||||
refresh_token_expired: configure.env.get(
|
||||
tokenExpired: configure.env.get('USER_TOKEN_EXPIRED', (v) => toNumber(v), 1800),
|
||||
refreshTokenExpired: configure.env.get(
|
||||
'USER_REFRESH_TOKEN_EXPIRED',
|
||||
(v) => toNumber(v),
|
||||
3600 * 30,
|
||||
|
@ -13,7 +13,7 @@ export class AccessTokenEntity extends BaseToken {
|
||||
* 关联的刷新令牌
|
||||
*/
|
||||
@OneToOne(() => RefreshTokenEntity, (token) => token.accessToken, { cascade: true })
|
||||
refreshToken: string;
|
||||
refreshToken: RefreshTokenEntity;
|
||||
|
||||
/**
|
||||
* 关联用户
|
||||
|
@ -15,7 +15,7 @@ export abstract class BaseToken extends BaseEntity {
|
||||
@Column({
|
||||
comment: '令牌过期时间',
|
||||
})
|
||||
expired_at: Date;
|
||||
expiredAt: Date;
|
||||
|
||||
@CreateDateColumn({
|
||||
comment: '令牌创建时间',
|
||||
|
142
src/modules/user/services/token.service.ts
Normal file
142
src/modules/user/services/token.service.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -19,11 +19,11 @@ export interface JwtConfig {
|
||||
/**
|
||||
* token过期时间
|
||||
*/
|
||||
token_expired: number;
|
||||
tokenExpired: number;
|
||||
/**
|
||||
* refresh token
|
||||
*/
|
||||
refresh_token_expired: number;
|
||||
refreshTokenExpired: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user