Spaces:
Sleeping
Sleeping
feat: Add role
Browse files- backend/package-lock.json +66 -0
- backend/package.json +4 -0
- backend/src/modules/authentication/authentication.controller.ts +4 -2
- backend/src/modules/authentication/authentication.module.ts +5 -0
- backend/src/modules/authentication/authentication.service.ts +2 -5
- backend/src/modules/authentication/{enums/index.ts → authorization/enums/role.enum.ts} +0 -0
- backend/src/modules/authentication/authorization/roles.decorator.ts +5 -0
- backend/src/modules/authentication/authorization/roles.guard.ts +22 -0
- backend/src/modules/user/user.service.ts +4 -1
backend/package-lock.json
CHANGED
@@ -14,6 +14,7 @@
|
|
14 |
"@nestjs/core": "^10.0.0",
|
15 |
"@nestjs/jwt": "^10.2.0",
|
16 |
"@nestjs/mapped-types": "*",
|
|
|
17 |
"@nestjs/platform-express": "^10.0.0",
|
18 |
"@nestjs/typeorm": "^10.0.2",
|
19 |
"bcrypt": "^5.1.1",
|
@@ -23,6 +24,9 @@
|
|
23 |
"mysql2": "^3.11.3",
|
24 |
"nest-access-control": "^3.1.0",
|
25 |
"nestjs-paginate": "^9.3.0",
|
|
|
|
|
|
|
26 |
"pg": "^8.13.0",
|
27 |
"reflect-metadata": "^0.2.0",
|
28 |
"rxjs": "^7.8.1",
|
@@ -1820,6 +1824,16 @@
|
|
1820 |
}
|
1821 |
}
|
1822 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1823 |
"node_modules/@nestjs/platform-express": {
|
1824 |
"version": "10.4.3",
|
1825 |
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.3.tgz",
|
@@ -7555,6 +7569,53 @@
|
|
7555 |
"node": ">= 0.8"
|
7556 |
}
|
7557 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7558 |
"node_modules/path-exists": {
|
7559 |
"version": "4.0.0",
|
7560 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
@@ -7620,6 +7681,11 @@
|
|
7620 |
"node": ">=8"
|
7621 |
}
|
7622 |
},
|
|
|
|
|
|
|
|
|
|
|
7623 |
"node_modules/pg": {
|
7624 |
"version": "8.13.0",
|
7625 |
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.0.tgz",
|
|
|
14 |
"@nestjs/core": "^10.0.0",
|
15 |
"@nestjs/jwt": "^10.2.0",
|
16 |
"@nestjs/mapped-types": "*",
|
17 |
+
"@nestjs/passport": "^10.0.3",
|
18 |
"@nestjs/platform-express": "^10.0.0",
|
19 |
"@nestjs/typeorm": "^10.0.2",
|
20 |
"bcrypt": "^5.1.1",
|
|
|
24 |
"mysql2": "^3.11.3",
|
25 |
"nest-access-control": "^3.1.0",
|
26 |
"nestjs-paginate": "^9.3.0",
|
27 |
+
"passport": "^0.7.0",
|
28 |
+
"passport-jwt": "^4.0.1",
|
29 |
+
"passport-local": "^1.0.0",
|
30 |
"pg": "^8.13.0",
|
31 |
"reflect-metadata": "^0.2.0",
|
32 |
"rxjs": "^7.8.1",
|
|
|
1824 |
}
|
1825 |
}
|
1826 |
},
|
1827 |
+
"node_modules/@nestjs/passport": {
|
1828 |
+
"version": "10.0.3",
|
1829 |
+
"resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz",
|
1830 |
+
"integrity": "sha512-znJ9Y4S8ZDVY+j4doWAJ8EuuVO7SkQN3yOBmzxbGaXbvcSwFDAdGJ+OMCg52NdzIO4tQoN4pYKx8W6M0ArfFRQ==",
|
1831 |
+
"license": "MIT",
|
1832 |
+
"peerDependencies": {
|
1833 |
+
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
1834 |
+
"passport": "^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0"
|
1835 |
+
}
|
1836 |
+
},
|
1837 |
"node_modules/@nestjs/platform-express": {
|
1838 |
"version": "10.4.3",
|
1839 |
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.3.tgz",
|
|
|
7569 |
"node": ">= 0.8"
|
7570 |
}
|
7571 |
},
|
7572 |
+
"node_modules/passport": {
|
7573 |
+
"version": "0.7.0",
|
7574 |
+
"resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
|
7575 |
+
"integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
|
7576 |
+
"license": "MIT",
|
7577 |
+
"dependencies": {
|
7578 |
+
"passport-strategy": "1.x.x",
|
7579 |
+
"pause": "0.0.1",
|
7580 |
+
"utils-merge": "^1.0.1"
|
7581 |
+
},
|
7582 |
+
"engines": {
|
7583 |
+
"node": ">= 0.4.0"
|
7584 |
+
},
|
7585 |
+
"funding": {
|
7586 |
+
"type": "github",
|
7587 |
+
"url": "https://github.com/sponsors/jaredhanson"
|
7588 |
+
}
|
7589 |
+
},
|
7590 |
+
"node_modules/passport-jwt": {
|
7591 |
+
"version": "4.0.1",
|
7592 |
+
"resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz",
|
7593 |
+
"integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==",
|
7594 |
+
"license": "MIT",
|
7595 |
+
"dependencies": {
|
7596 |
+
"jsonwebtoken": "^9.0.0",
|
7597 |
+
"passport-strategy": "^1.0.0"
|
7598 |
+
}
|
7599 |
+
},
|
7600 |
+
"node_modules/passport-local": {
|
7601 |
+
"version": "1.0.0",
|
7602 |
+
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
|
7603 |
+
"integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==",
|
7604 |
+
"dependencies": {
|
7605 |
+
"passport-strategy": "1.x.x"
|
7606 |
+
},
|
7607 |
+
"engines": {
|
7608 |
+
"node": ">= 0.4.0"
|
7609 |
+
}
|
7610 |
+
},
|
7611 |
+
"node_modules/passport-strategy": {
|
7612 |
+
"version": "1.0.0",
|
7613 |
+
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
7614 |
+
"integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==",
|
7615 |
+
"engines": {
|
7616 |
+
"node": ">= 0.4.0"
|
7617 |
+
}
|
7618 |
+
},
|
7619 |
"node_modules/path-exists": {
|
7620 |
"version": "4.0.0",
|
7621 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
|
|
7681 |
"node": ">=8"
|
7682 |
}
|
7683 |
},
|
7684 |
+
"node_modules/pause": {
|
7685 |
+
"version": "0.0.1",
|
7686 |
+
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
7687 |
+
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
7688 |
+
},
|
7689 |
"node_modules/pg": {
|
7690 |
"version": "8.13.0",
|
7691 |
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.0.tgz",
|
backend/package.json
CHANGED
@@ -30,6 +30,7 @@
|
|
30 |
"@nestjs/core": "^10.0.0",
|
31 |
"@nestjs/jwt": "^10.2.0",
|
32 |
"@nestjs/mapped-types": "*",
|
|
|
33 |
"@nestjs/platform-express": "^10.0.0",
|
34 |
"@nestjs/typeorm": "^10.0.2",
|
35 |
"bcrypt": "^5.1.1",
|
@@ -39,6 +40,9 @@
|
|
39 |
"mysql2": "^3.11.3",
|
40 |
"nest-access-control": "^3.1.0",
|
41 |
"nestjs-paginate": "^9.3.0",
|
|
|
|
|
|
|
42 |
"pg": "^8.13.0",
|
43 |
"reflect-metadata": "^0.2.0",
|
44 |
"rxjs": "^7.8.1",
|
|
|
30 |
"@nestjs/core": "^10.0.0",
|
31 |
"@nestjs/jwt": "^10.2.0",
|
32 |
"@nestjs/mapped-types": "*",
|
33 |
+
"@nestjs/passport": "^10.0.3",
|
34 |
"@nestjs/platform-express": "^10.0.0",
|
35 |
"@nestjs/typeorm": "^10.0.2",
|
36 |
"bcrypt": "^5.1.1",
|
|
|
40 |
"mysql2": "^3.11.3",
|
41 |
"nest-access-control": "^3.1.0",
|
42 |
"nestjs-paginate": "^9.3.0",
|
43 |
+
"passport": "^0.7.0",
|
44 |
+
"passport-jwt": "^4.0.1",
|
45 |
+
"passport-local": "^1.0.0",
|
46 |
"pg": "^8.13.0",
|
47 |
"reflect-metadata": "^0.2.0",
|
48 |
"rxjs": "^7.8.1",
|
backend/src/modules/authentication/authentication.controller.ts
CHANGED
@@ -7,12 +7,14 @@ import {
|
|
7 |
Post,
|
8 |
Request,
|
9 |
} from '@nestjs/common';
|
10 |
-
import { AuthenticationGuard } from './authentication.guard.js';
|
11 |
import { AuthenticationService } from './authentication.service.js';
|
12 |
import { Public } from './authentication.decorator.js';
|
13 |
import { SignInDto } from './dto/sign-in.dto.js';
|
14 |
import { SignUpDto } from './dto/sign-up.dto.js';
|
|
|
|
|
15 |
@Controller('authentication')
|
|
|
16 |
export class AuthenticationController {
|
17 |
constructor(private AuthenticationService: AuthenticationService) {}
|
18 |
|
@@ -30,8 +32,8 @@ export class AuthenticationController {
|
|
30 |
return this.AuthenticationService.signUp(signUpDto);
|
31 |
}
|
32 |
|
33 |
-
// @UseGuards(AuthenticationGuard)
|
34 |
@Get('profile')
|
|
|
35 |
getProfile(@Request() req) {
|
36 |
const userId = req.user.sub;
|
37 |
return this.AuthenticationService.getProfile(userId);
|
|
|
7 |
Post,
|
8 |
Request,
|
9 |
} from '@nestjs/common';
|
|
|
10 |
import { AuthenticationService } from './authentication.service.js';
|
11 |
import { Public } from './authentication.decorator.js';
|
12 |
import { SignInDto } from './dto/sign-in.dto.js';
|
13 |
import { SignUpDto } from './dto/sign-up.dto.js';
|
14 |
+
import { Roles } from './authorization/roles.decorator.js';
|
15 |
+
import { Role } from './authorization/enums/role.enum.js';
|
16 |
@Controller('authentication')
|
17 |
+
|
18 |
export class AuthenticationController {
|
19 |
constructor(private AuthenticationService: AuthenticationService) {}
|
20 |
|
|
|
32 |
return this.AuthenticationService.signUp(signUpDto);
|
33 |
}
|
34 |
|
|
|
35 |
@Get('profile')
|
36 |
+
@Roles(Role.CUSTOMER)
|
37 |
getProfile(@Request() req) {
|
38 |
const userId = req.user.sub;
|
39 |
return this.AuthenticationService.getProfile(userId);
|
backend/src/modules/authentication/authentication.module.ts
CHANGED
@@ -6,6 +6,7 @@ import { AuthenticationController } from './authentication.controller.js';
|
|
6 |
import { AuthenticationGuard } from './authentication.guard.js';
|
7 |
import { APP_GUARD } from '@nestjs/core';
|
8 |
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
|
9 |
@Module({
|
10 |
imports: [
|
11 |
UserModule,
|
@@ -23,6 +24,10 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
23 |
{
|
24 |
provide: APP_GUARD,
|
25 |
useClass: AuthenticationGuard,
|
|
|
|
|
|
|
|
|
26 |
}
|
27 |
],
|
28 |
controllers: [AuthenticationController],
|
|
|
6 |
import { AuthenticationGuard } from './authentication.guard.js';
|
7 |
import { APP_GUARD } from '@nestjs/core';
|
8 |
import { ConfigModule, ConfigService } from '@nestjs/config';
|
9 |
+
import { RolesGuard } from './authorization/roles.guard.js';
|
10 |
@Module({
|
11 |
imports: [
|
12 |
UserModule,
|
|
|
24 |
{
|
25 |
provide: APP_GUARD,
|
26 |
useClass: AuthenticationGuard,
|
27 |
+
},
|
28 |
+
{
|
29 |
+
provide: APP_GUARD,
|
30 |
+
useClass: RolesGuard,
|
31 |
}
|
32 |
],
|
33 |
controllers: [AuthenticationController],
|
backend/src/modules/authentication/authentication.service.ts
CHANGED
@@ -23,7 +23,7 @@ export class AuthenticationService {
|
|
23 |
if (!user || (await !bcrypt.compare(pass, user.hash_password))) {
|
24 |
throw new UnauthorizedException();
|
25 |
}
|
26 |
-
const payload = { sub: user.id, username: user.id };
|
27 |
return {
|
28 |
access_token: await this.jwtService.signAsync(payload),
|
29 |
};
|
@@ -49,13 +49,10 @@ export class AuthenticationService {
|
|
49 |
email: email,
|
50 |
password: hash_password
|
51 |
})
|
52 |
-
console.log(user)
|
53 |
await this.usersService.save(user);
|
54 |
|
55 |
-
const payload = { sub: user.id, username: user.id };
|
56 |
-
console.log("payload: ", payload);
|
57 |
const token = await this.jwtService.signAsync(payload)
|
58 |
-
console.log("token: ", token);
|
59 |
return {
|
60 |
access_token: token
|
61 |
};
|
|
|
23 |
if (!user || (await !bcrypt.compare(pass, user.hash_password))) {
|
24 |
throw new UnauthorizedException();
|
25 |
}
|
26 |
+
const payload = { sub: user.id, username: user.id, roles: user.role.role_name};
|
27 |
return {
|
28 |
access_token: await this.jwtService.signAsync(payload),
|
29 |
};
|
|
|
49 |
email: email,
|
50 |
password: hash_password
|
51 |
})
|
|
|
52 |
await this.usersService.save(user);
|
53 |
|
54 |
+
const payload = { sub: user.id, username: user.id, role: user.role };
|
|
|
55 |
const token = await this.jwtService.signAsync(payload)
|
|
|
56 |
return {
|
57 |
access_token: token
|
58 |
};
|
backend/src/modules/authentication/{enums/index.ts → authorization/enums/role.enum.ts}
RENAMED
File without changes
|
backend/src/modules/authentication/authorization/roles.decorator.ts
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// src/decorators/roles.decorator.ts
|
2 |
+
import { SetMetadata } from '@nestjs/common';
|
3 |
+
|
4 |
+
export const ROLES_KEY = 'roles';
|
5 |
+
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
|
backend/src/modules/authentication/authorization/roles.guard.ts
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
3 |
+
import { Reflector } from '@nestjs/core';
|
4 |
+
import { Role } from 'nest-access-control';
|
5 |
+
import { ROLES_KEY } from './roles.decorator.js';
|
6 |
+
|
7 |
+
@Injectable()
|
8 |
+
export class RolesGuard implements CanActivate {
|
9 |
+
constructor(private reflector: Reflector) {}
|
10 |
+
|
11 |
+
canActivate(context: ExecutionContext): boolean {
|
12 |
+
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
|
13 |
+
context.getHandler(),
|
14 |
+
context.getClass(),
|
15 |
+
]);
|
16 |
+
if (!requiredRoles) {
|
17 |
+
return true;
|
18 |
+
}
|
19 |
+
const { user } = context.switchToHttp().getRequest();
|
20 |
+
return requiredRoles.some((role) => user.roles.includes(role));
|
21 |
+
}
|
22 |
+
}
|
backend/src/modules/user/user.service.ts
CHANGED
@@ -26,6 +26,9 @@ export class UserService {
|
|
26 |
}
|
27 |
|
28 |
async findOneByField(field: string, value: any): Promise<UserEntity | undefined> {
|
29 |
-
return UserEntity.findOne({
|
|
|
|
|
|
|
30 |
}
|
31 |
}
|
|
|
26 |
}
|
27 |
|
28 |
async findOneByField(field: string, value: any): Promise<UserEntity | undefined> {
|
29 |
+
return UserEntity.findOne({
|
30 |
+
where: { [field]: value },
|
31 |
+
relations: ['role']
|
32 |
+
});
|
33 |
}
|
34 |
}
|