auth
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AuthorizationService } from './authorization.service';
|
||||
import { Permission } from './entities/permission.entity';
|
||||
import { UserPermission } from './entities/user-permission.entity';
|
||||
import { CustomerPolicy } from './policies/customer.policy';
|
||||
import { SalonPolicy } from './policies/salon.policy';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Permission, UserPermission])],
|
||||
providers: [AuthorizationService, SalonPolicy, CustomerPolicy],
|
||||
exports: [AuthorizationService, SalonPolicy, CustomerPolicy],
|
||||
})
|
||||
export class AuthorizationModule {}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { UserRole } from '../users/enums/user-role.enum';
|
||||
import { AuthUser } from '../auth/interfaces/auth-user.interface';
|
||||
import { UserPermission } from './entities/user-permission.entity';
|
||||
|
||||
@Injectable()
|
||||
export class AuthorizationService {
|
||||
constructor(
|
||||
@InjectRepository(UserPermission)
|
||||
private readonly userPermissionsRepository: Repository<UserPermission>,
|
||||
) {}
|
||||
|
||||
async loadPermissions(userId: string): Promise<string[]> {
|
||||
const userPermissions = await this.userPermissionsRepository.find({
|
||||
where: { userId },
|
||||
relations: { permission: true },
|
||||
});
|
||||
|
||||
return userPermissions.map((up) => up.permission.code);
|
||||
}
|
||||
|
||||
hasPermission(user: AuthUser, code: string): boolean {
|
||||
return user.permissions.includes(code);
|
||||
}
|
||||
|
||||
isAdmin(user: AuthUser): boolean {
|
||||
return user.role === UserRole.ADMIN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
@Entity('permissions')
|
||||
export class Permission {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ unique: true })
|
||||
code: string;
|
||||
|
||||
@Column()
|
||||
description: string;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
import { Permission } from './permission.entity';
|
||||
|
||||
@Entity('user_permissions')
|
||||
@Unique(['userId', 'permissionId'])
|
||||
export class UserPermission {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@Column()
|
||||
permissionId: string;
|
||||
|
||||
@ManyToOne(() => User, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@ManyToOne(() => Permission, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'permissionId' })
|
||||
permission: Permission;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export enum PermissionCode {
|
||||
USERS_READ = 'users:read',
|
||||
USERS_WRITE = 'users:write',
|
||||
USERS_DELETE = 'users:delete',
|
||||
SALONS_READ = 'salons:read',
|
||||
SALONS_WRITE = 'salons:write',
|
||||
SALONS_DELETE = 'salons:delete',
|
||||
CUSTOMERS_READ = 'customers:read',
|
||||
CUSTOMERS_WRITE = 'customers:write',
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthUser } from '../../auth/interfaces/auth-user.interface';
|
||||
import { Customer } from '../../customers/entities/customer.entity';
|
||||
import { UserRole } from '../../users/enums/user-role.enum';
|
||||
import { AuthorizationService } from '../authorization.service';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerPolicy {
|
||||
constructor(private readonly authorizationService: AuthorizationService) {}
|
||||
|
||||
canRead(user: AuthUser, customer: Customer): boolean {
|
||||
if (this.authorizationService.isAdmin(user)) {
|
||||
return true;
|
||||
}
|
||||
if (user.role === UserRole.CUSTOMER) {
|
||||
return customer.userId === user.id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
canUpdate(user: AuthUser, customer: Customer): boolean {
|
||||
if (this.authorizationService.isAdmin(user)) {
|
||||
return true;
|
||||
}
|
||||
if (user.role === UserRole.CUSTOMER) {
|
||||
return customer.userId === user.id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthUser } from '../../auth/interfaces/auth-user.interface';
|
||||
import { Salon } from '../../salons/entities/salon.entity';
|
||||
import { UserRole } from '../../users/enums/user-role.enum';
|
||||
import { AuthorizationService } from '../authorization.service';
|
||||
|
||||
@Injectable()
|
||||
export class SalonPolicy {
|
||||
constructor(private readonly authorizationService: AuthorizationService) {}
|
||||
|
||||
canRead(user: AuthUser, salon: Salon): boolean {
|
||||
if (this.authorizationService.isAdmin(user)) {
|
||||
return true;
|
||||
}
|
||||
if (user.role === UserRole.SALON) {
|
||||
return salon.ownerId === user.id;
|
||||
}
|
||||
if (user.role === UserRole.CUSTOMER) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
canUpdate(user: AuthUser, salon: Salon): boolean {
|
||||
if (this.authorizationService.isAdmin(user)) {
|
||||
return true;
|
||||
}
|
||||
if (user.role === UserRole.SALON) {
|
||||
return salon.ownerId === user.id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
canDelete(user: AuthUser, salon: Salon): boolean {
|
||||
if (this.authorizationService.isAdmin(user)) {
|
||||
return true;
|
||||
}
|
||||
if (user.role === UserRole.SALON) {
|
||||
return salon.ownerId === user.id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user