feat: add signout

This commit is contained in:
Innei
2022-06-11 11:26:38 +08:00
committed by
parent 15a9d09c0e
commit 136734a55b
3 changed files with 61 additions and 37 deletions

View File

@@ -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)
}
}

View File

@@ -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, 时间)
*

View File

@@ -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
}