feat: add generic from payload data
Some checks failed
Publish / Publish Job (push) Has been cancelled

This commit is contained in:
Дмитрий
2026-03-27 11:36:20 +03:00
parent be0d92d7d7
commit d49b2cf7e5
2 changed files with 19 additions and 34 deletions

View File

@@ -1,13 +1,3 @@
export interface TokenPayload { export type VerifyResult<T = any> =
sub: string | { valid: true; payload: T; jti: string }
}
// роли храним в токене
export interface TokenRolePayload {
id: string | number
name: string
}
export type VerifyResult =
| { valid: true; userId: string; jti: string; role: TokenRolePayload }
| { valid: false; reason: string } | { valid: false; reason: string }

View File

@@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'
import { createHmac, randomUUID } from 'crypto' import { createHmac, randomUUID } from 'crypto'
import { PASSPORT_OPTIONS } from './constants' import { PASSPORT_OPTIONS } from './constants'
import { PassportOptions, TokenRolePayload } from './interfaces' import { PassportOptions } from './interfaces'
import { base64UrlDecode, base64UrlEncode, constantTimeEqual } from './utils' import { base64UrlDecode, base64UrlEncode, constantTimeEqual } from './utils'
const TOKEN_TYPES = { const TOKEN_TYPES = {
@@ -24,9 +24,8 @@ export class PassportService {
this.SECRET_KEY = options.secretKey this.SECRET_KEY = options.secretKey
} }
public generate( public generate<T extends Record<string, any>>(
userId: string, payload: T,
role: TokenRolePayload,
ttl: number, ttl: number,
tokenType: TokenType = TOKEN_TYPES.AUTH tokenType: TokenType = TOKEN_TYPES.AUTH
) { ) {
@@ -35,38 +34,38 @@ export class PassportService {
const jti = randomUUID() const jti = randomUUID()
const userPart = base64UrlEncode(userId) const payloadPart = base64UrlEncode(JSON.stringify(payload))
const rolePart = base64UrlEncode(JSON.stringify(role))
const iatPart = base64UrlEncode(String(issuedAt)) const iatPart = base64UrlEncode(String(issuedAt))
const expPart = base64UrlEncode(String(expiresAt)) const expPart = base64UrlEncode(String(expiresAt))
const jtiPart = base64UrlEncode(jti) const jtiPart = base64UrlEncode(jti)
const serialized = this.serialize( const serialized = this.serialize(
tokenType, tokenType,
userPart, payloadPart,
rolePart,
iatPart, iatPart,
expPart, expPart,
jtiPart jtiPart
) )
const mac = this.computeHmac(this.SECRET_KEY, serialized) const mac = this.computeHmac(this.SECRET_KEY, serialized)
return `${userPart}.${rolePart}.${iatPart}.${expPart}.${jtiPart}.${mac}` return `${payloadPart}.${iatPart}.${expPart}.${jtiPart}.${mac}`
} }
public verify(token: string, expectedType: TokenType = TOKEN_TYPES.AUTH) { public verify<T = any>(
token: string,
expectedType: TokenType = TOKEN_TYPES.AUTH
) {
try { try {
const parts = token.split('.') const parts = token.split('.')
if (parts.length !== 6) if (parts.length !== 5)
return { valid: false, reason: 'Не верный формат токена.' } return { valid: false, reason: 'Не верный формат токена.' }
const [userPart, rolePart, iatPart, expPart, jtiPart, mac] = parts const [payloadPart, iatPart, expPart, jtiPart, mac] = parts
const serialized = this.serialize( const serialized = this.serialize(
expectedType, expectedType,
userPart, payloadPart,
rolePart,
iatPart, iatPart,
expPart, expPart,
jtiPart jtiPart
@@ -87,13 +86,10 @@ export class PassportService {
if (this.now() > expNumber) if (this.now() > expNumber)
return { valid: false, reason: 'Срок действия токена истёк.' } return { valid: false, reason: 'Срок действия токена истёк.' }
const decodedRole = JSON.parse( const decodedPayload = JSON.parse(base64UrlDecode(payloadPart)) as T
base64UrlDecode(rolePart)
) as TokenRolePayload
return { return {
valid: true, valid: true,
userId: base64UrlDecode(userPart), payload: decodedPayload,
role: decodedRole,
jti: base64UrlDecode(jtiPart) jti: base64UrlDecode(jtiPart)
} }
} catch (error) { } catch (error) {
@@ -107,13 +103,12 @@ export class PassportService {
private serialize( private serialize(
domain: string, domain: string,
user: string, payload: string,
role: string,
iat: string, iat: string,
exp: string, exp: string,
jti: string jti: string
) { ) {
return [domain, user, role, iat, exp, jti].join( return [domain, payload, iat, exp, jti].join(
PassportService.INTERNAL_SEPARATOR PassportService.INTERNAL_SEPARATOR
) )
} }