feat: add generic from payload data
Some checks failed
Publish / Publish Job (push) Has been cancelled
Some checks failed
Publish / Publish Job (push) Has been cancelled
This commit is contained in:
@@ -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 }
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user