feat: updade workspace
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
export interface ApiResponse<T> {
|
||||
success: true;
|
||||
data: T;
|
||||
meta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function ok<T>(data: T, meta?: Record<string, unknown>): ApiResponse<T> {
|
||||
return meta === undefined ? { success: true, data } : { success: true, data, meta };
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { Request } from 'express';
|
||||
|
||||
export type Role = 'ADMIN' | 'MANAGER' | 'EMPLOYEE';
|
||||
|
||||
export interface JwtUser {
|
||||
sub: number;
|
||||
email: string;
|
||||
role: Role;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AuthenticatedRequest extends Request {
|
||||
user: JwtUser;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
import type { AuthenticatedRequest, JwtUser } from './auth.types.js';
|
||||
|
||||
export const CurrentUser = createParamDecorator((_data: unknown, context: ExecutionContext): JwtUser => {
|
||||
const request = context.switchToHttp().getRequest<AuthenticatedRequest>();
|
||||
return request.user;
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import type { Request } from 'express';
|
||||
import type { AuthenticatedRequest, JwtUser } from './auth.types.js';
|
||||
|
||||
function readCookieToken(request: Request): string | undefined {
|
||||
const header = request.headers.cookie;
|
||||
if (header === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const tokenPair = header
|
||||
.split(';')
|
||||
.map((part) => part.trim())
|
||||
.find((part) => part.startsWith('okr_token='));
|
||||
return tokenPair?.slice('okr_token='.length);
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard implements CanActivate {
|
||||
constructor(@Inject(JwtService) private readonly jwtService: JwtService) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const request = context.switchToHttp().getRequest<AuthenticatedRequest>();
|
||||
const authHeader = request.headers.authorization;
|
||||
const bearer = authHeader?.startsWith('Bearer ') === true ? authHeader.slice(7) : undefined;
|
||||
const token = bearer ?? readCookieToken(request);
|
||||
if (token === undefined || token.length === 0) {
|
||||
throw new UnauthorizedException('Authentication required');
|
||||
}
|
||||
|
||||
try {
|
||||
request.user = this.jwtService.verify<JwtUser>(token);
|
||||
return true;
|
||||
} catch {
|
||||
throw new UnauthorizedException('Invalid or expired token');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
import type { Role } from './auth.types.js';
|
||||
|
||||
export const ROLES_KEY = 'roles';
|
||||
export const Roles = (...roles: Role[]): ReturnType<typeof SetMetadata> => SetMetadata(ROLES_KEY, roles);
|
||||
@@ -0,0 +1,25 @@
|
||||
import { CanActivate, ExecutionContext, ForbiddenException, Inject, Injectable } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import type { AuthenticatedRequest, Role } from './auth.types.js';
|
||||
import { ROLES_KEY } from './roles.decorator.js';
|
||||
|
||||
@Injectable()
|
||||
export class RolesGuard implements CanActivate {
|
||||
constructor(@Inject(Reflector) private readonly reflector: Reflector) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const roles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (roles === undefined || roles.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest<AuthenticatedRequest>();
|
||||
if (!roles.includes(request.user.role)) {
|
||||
throw new ForbiddenException('Insufficient role');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user