diff --git a/src/modules/user/user.controller.ts b/src/modules/user/user.controller.ts index 007e30a4..0787d067 100644 --- a/src/modules/user/user.controller.ts +++ b/src/modules/user/user.controller.ts @@ -55,7 +55,6 @@ export class UserController { url, mail, avatar, - expiresIn: 7, id, } } @@ -79,4 +78,9 @@ export class UserController { ) { return await this.userService.patchUserData(user, body) } + + @Post('signout') + async singout(@CurrentUser() user: any) { + return this.userService.signout(user.token) + } } diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index d621f40f..ed5f45cb 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -81,7 +81,7 @@ export class UserService { // @ts-ignore const res = await this.userModel.create({ ...model }) - const token = await this.authService.jwtServicePublic.sign(res._id) + const token = this.authService.jwtServicePublic.sign(res._id) return { token, username: res.username } } @@ -112,11 +112,15 @@ export class UserService { } // 2. 撤销所有 token - await this.authService.jwtServicePublic.invokeAll() + await this.authService.jwtServicePublic.revokeAll() } return await this.userModel.updateOne({ _id: user._id }, doc) } + signout(token: string) { + return this.authService.jwtServicePublic.revokeToken(token) + } + /** * 记录登陆的足迹(ip, 时间) * diff --git a/src/processors/helper/helper.jwt.service.ts b/src/processors/helper/helper.jwt.service.ts index a80688cc..7c1132a2 100644 --- a/src/processors/helper/helper.jwt.service.ts +++ b/src/processors/helper/helper.jwt.service.ts @@ -1,5 +1,5 @@ import cluster from 'cluster' -import { SignOptions, sign, verify } from 'jsonwebtoken' +import { sign, verify } from 'jsonwebtoken' import { machineIdSync } from 'node-machine-id' import { Injectable } from '@nestjs/common' @@ -10,37 +10,47 @@ import { getRedisKey, md5 } from '~/utils' import { CacheService } from '../cache/cache.service' -const getMachineId = () => { - const id = machineIdSync() - - if (isDev && cluster.isPrimary) { - console.log(id) - } - return id -} -const secret = - SECURITY.jwtSecret || - Buffer.from(getMachineId()).toString('base64').slice(0, 15) || - 'asjhczxiucipoiopiqm2376' - -if (isDev && cluster.isPrimary) { - console.log(secret) -} -if (!CLUSTER.enable || cluster.isPrimary) { - console.log( - 'JWT Secret start with :', - secret.slice(0, 5) + '*'.repeat(secret.length - 5), - ) -} - @Injectable() export class JWTService { - constructor(private readonly cacheService: CacheService) {} + private secret = '' + constructor(private readonly cacheService: CacheService) { + this.init() + } + + init() { + if (this.secret) { + return + } + + const getMachineId = () => { + const id = machineIdSync() + + if (isDev && cluster.isPrimary) { + console.log(id) + } + return id + } + const secret = + SECURITY.jwtSecret || + Buffer.from(getMachineId()).toString('base64').slice(0, 15) || + 'asjhczxiucipoiopiqm2376' + + if (isDev && cluster.isPrimary) { + console.log(secret) + } + if (!CLUSTER.enable || cluster.isPrimary) { + console.log( + 'JWT Secret start with :', + secret.slice(0, 5) + '*'.repeat(secret.length - 5), + ) + } + this.secret = secret + } async verify(token: string) { try { - verify(token, secret) - return await this.isTokenInRedis(token) + verify(token, this.secret) + return isDev ? true : await this.isTokenInRedis(token) } catch (er) { console.debug(er, token) @@ -51,17 +61,17 @@ export class JWTService { async isTokenInRedis(token: string) { const redis = this.cacheService.getClient() const key = getRedisKey(RedisKeys.JWTStore) - const has = await redis.sismember(key, md5(token)) + const has = await redis.hexists(key, md5(token)) return !!has } - async invokeToken(token: string) { + async revokeToken(token: string) { const redis = this.cacheService.getClient() const key = getRedisKey(RedisKeys.JWTStore) - await redis.srem(key, md5(token)) + await redis.hdel(key, md5(token)) } - async invokeAll() { + async revokeAll() { const redis = this.cacheService.getClient() const key = getRedisKey(RedisKeys.JWTStore) await redis.del(key) @@ -69,11 +79,17 @@ export class JWTService { async storeTokenInRedis(token: string) { const redis = this.cacheService.getClient() - await redis.sadd(getRedisKey(RedisKeys.JWTStore), md5(token)) + await redis.hset( + getRedisKey(RedisKeys.JWTStore), + md5(token), + JSON.stringify({ + date: new Date().toISOString(), + }), + ) } - sign(id: string, options: SignOptions = { expiresIn: '7d' }) { - const token = sign({ id }, secret, options) + sign(id: string) { + const token = sign({ id }, this.secret) this.storeTokenInRedis(token) return token }