Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
classwork-92
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Нұрасыл Қайратұлы
classwork-92
Commits
42a92e0e
Commit
42a92e0e
authored
May 01, 2025
by
Нұрасыл Қайратұлы
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix roles
parent
93bc8158
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
161 additions
and
58 deletions
+161
-58
App.tsx
client/src/App.tsx
+11
-11
ProtectedRoute.tsx
client/src/components/UI/ProtectedRoute.tsx
+3
-4
Auth.tsx
client/src/containers/Auth.tsx
+1
-0
Products.tsx
client/src/containers/Products.tsx
+10
-7
app.module.ts
server/src/app.module.ts
+8
-1
auth.controller.ts
server/src/auth/auth.controller.ts
+1
-1
auth.module.ts
server/src/auth/auth.module.ts
+4
-3
auth.service.ts
server/src/auth/auth.service.ts
+17
-9
register.dto.ts
server/src/auth/dto/register.dto.ts
+3
-0
roles.ts
server/src/common/constants/roles.ts
+4
-0
roles.decarator.ts
server/src/common/decorators/roles.decarator.ts
+4
-0
jwt-auth.guard.ts
server/src/common/guards/jwt-auth.guard.ts
+0
-0
roles.guard.ts
server/src/common/guards/roles.guard.ts
+48
-0
jwt.strategy.ts
server/src/common/strategy/jwt.strategy.ts
+4
-4
product.controller.ts
server/src/product/product.controller.ts
+9
-7
product.module.ts
server/src/product/product.module.ts
+5
-5
seed.module.ts
server/src/seed/seed.module.ts
+5
-4
seed.service.ts
server/src/seed/seed.service.ts
+17
-2
create-user.dto.ts
server/src/user/dto/create-user.dto.ts
+3
-0
user.entity.ts
server/src/user/entities/user.entity.ts
+4
-0
No files found.
client/src/App.tsx
View file @
42a92e0e
import
{
Box
,
Container
,
CssBaseline
}
from
'@mui/material'
;
import
{
AppToolBar
}
from
'./components/UI/AppToolbar'
;
import
{
Route
,
Routes
,
useNavigate
}
from
'react-router-dom'
;
import
{
Products
}
from
'./containers/Products'
;
import
{
NewProduct
}
from
'./containers/NewProduct'
;
import
Auth
from
'./containers/Auth'
;
import
{
ProtectedRoute
}
from
'./components/UI/ProtectedRoute'
;
import
{
useAppDispatch
,
useAppSelector
}
from
'./store/hooks'
;
import
{
shallowEqual
}
from
'react-redux'
;
import
{
useEffect
}
from
'react'
;
import
{
notification
}
from
'antd'
;
import
{
useEffect
}
from
'react'
;
import
{
shallowEqual
}
from
'react-redux'
;
import
{
Route
,
Routes
,
useNavigate
}
from
'react-router-dom'
;
import
'./App.css'
;
import
{
AppToolBar
}
from
'./components/UI/AppToolbar'
;
import
{
ProtectedRoute
}
from
'./components/UI/ProtectedRoute'
;
import
Auth
from
'./containers/Auth'
;
import
{
NewProduct
}
from
'./containers/NewProduct'
;
import
{
Products
}
from
'./containers/Products'
;
import
{
refreshToken
}
from
'./features/usersSlice'
;
import
{
useAppDispatch
,
useAppSelector
}
from
'./store/hooks'
;
function
App
()
{
const
dispatch
=
useAppDispatch
();
...
...
@@ -46,7 +46,7 @@ function App() {
<
Route
path=
"/"
element=
{
<
ProtectedRoute
user=
{
user
}
>
<
ProtectedRoute
isAllowed=
{
!!
user
}
>
<
Products
/>
</
ProtectedRoute
>
}
...
...
@@ -54,7 +54,7 @@ function App() {
<
Route
path=
"/products"
element=
{
<
ProtectedRoute
user=
{
user
}
>
<
ProtectedRoute
isAllowed=
{
!!
user
&&
user
.
role
===
'admin'
}
>
<
NewProduct
/>
</
ProtectedRoute
>
}
...
...
client/src/components/UI/ProtectedRoute.tsx
View file @
42a92e0e
import
{
IUser
}
from
'@/containers/Auth'
;
import
React
from
'react'
;
import
{
Navigate
}
from
'react-router-dom'
;
type
ProtectedRouteProps
=
{
user
:
IUser
|
null
;
isAllowed
:
boolean
;
children
:
React
.
ReactNode
;
};
export
const
ProtectedRoute
=
({
user
,
children
}:
ProtectedRouteProps
)
=>
{
if
(
!
user
)
{
export
const
ProtectedRoute
=
({
isAllowed
,
children
}:
ProtectedRouteProps
)
=>
{
if
(
!
isAllowed
)
{
return
<
Navigate
to=
"/auth"
replace
/>;
}
...
...
client/src/containers/Auth.tsx
View file @
42a92e0e
...
...
@@ -15,4 +15,5 @@ export interface IUser {
id
:
number
;
username
:
string
;
accessToken
:
string
;
role
:
string
;
}
client/src/containers/Products.tsx
View file @
42a92e0e
import
{
fetchProducts
}
from
'../features/productsSlice'
;
import
{
useAppDispatch
,
useAppSelector
}
from
'../store/hooks'
;
import
{
Button
,
Grid
,
Typography
}
from
'@mui/material'
;
import
{
useEffect
}
from
'react'
;
import
{
Link
}
from
'react-router-dom'
;
import
{
ProductItem
}
from
'../components/ProductItem'
;
import
{
fetchProducts
}
from
'../features/productsSlice'
;
import
{
useAppDispatch
,
useAppSelector
}
from
'../store/hooks'
;
export
const
Products
=
()
=>
{
const
dispatch
=
useAppDispatch
();
const
{
products
}
=
useAppSelector
((
state
)
=>
state
.
products
);
const
{
user
}
=
useAppSelector
((
state
)
=>
state
.
user
);
useEffect
(()
=>
{
dispatch
(
fetchProducts
());
...
...
@@ -34,11 +35,13 @@ export const Products = () => {
))
}
</
Grid
>
<
Grid
item
>
<
Button
color=
"primary"
component=
{
Link
}
to=
{
'/products'
}
>
Add Product
</
Button
>
</
Grid
>
{
user
?.
role
===
'admin'
&&
(
<
Grid
item
>
<
Button
color=
"primary"
component=
{
Link
}
to=
{
'/products'
}
>
Add Product
</
Button
>
</
Grid
>
)
}
</
Grid
>
</>
);
...
...
server/src/app.module.ts
View file @
42a92e0e
import
{
Module
}
from
'@nestjs/common'
;
import
{
APP_GUARD
}
from
'@nestjs/core'
;
import
{
TypeOrmModule
}
from
'@nestjs/typeorm'
;
import
{
AuthModule
}
from
'./auth/auth.module'
;
import
{
CategoryModule
}
from
'./category/category.module'
;
import
{
Category
}
from
'./category/entities/category.entity'
;
import
{
RolesGuard
}
from
'./common/guards/roles.guard'
;
import
{
Product
}
from
'./product/entities/product.entity'
;
import
{
ProductModule
}
from
'./product/product.module'
;
import
{
SeedModule
}
from
'./seed/seed.module'
;
...
...
@@ -30,6 +32,11 @@ import { UserModule } from './user/user.module';
SeedModule
,
],
controllers
:
[],
providers
:
[],
providers
:
[
{
provide
:
APP_GUARD
,
useClass
:
RolesGuard
,
},
],
})
export
class
AppModule
{}
server/src/auth/auth.controller.ts
View file @
42a92e0e
...
...
@@ -8,7 +8,7 @@ import {
Request
,
UseGuards
,
}
from
'@nestjs/common'
;
import
{
JwtAuthGuard
}
from
'src/common/guards/jwt-auth.guar
f
'
;
import
{
JwtAuthGuard
}
from
'src/common/guards/jwt-auth.guar
d
'
;
import
{
AuthService
}
from
'./auth.service'
;
import
{
RegisterDto
}
from
'./dto/register.dto'
;
...
...
server/src/auth/auth.module.ts
View file @
42a92e0e
import
{
Module
}
from
'@nestjs/common'
;
import
{
AuthService
}
from
'./auth.service'
;
import
{
AuthController
}
from
'./auth.controller'
;
import
{
UserModule
}
from
'src/user/user.module'
;
import
{
JwtModule
}
from
'@nestjs/jwt'
;
import
{
PassportModule
}
from
'@nestjs/passport'
;
import
{
JwtStrategy
}
from
'src/common/strategy/jwt.strategy'
;
import
{
UserModule
}
from
'src/user/user.module'
;
import
{
AuthController
}
from
'./auth.controller'
;
import
{
AuthService
}
from
'./auth.service'
;
@
Module
({
imports
:
[
...
...
@@ -18,5 +18,6 @@ import { JwtStrategy } from 'src/common/strategy/jwt.strategy';
],
controllers
:
[
AuthController
],
providers
:
[
AuthService
,
JwtStrategy
],
exports
:
[
AuthService
],
})
export
class
AuthModule
{}
server/src/auth/auth.service.ts
View file @
42a92e0e
...
...
@@ -18,8 +18,10 @@ export class AuthService {
)
{}
async
register
(
registerAuthDto
:
RegisterDto
)
{
const
{
accessToken
,
refreshToken
}
=
await
this
.
generateToken
(
registerAuthDto
);
const
{
accessToken
,
refreshToken
}
=
await
this
.
generateToken
({
role
:
registerAuthDto
.
role
,
username
:
registerAuthDto
.
username
,
});
const
salt
=
await
bcrypt
.
genSalt
(
SALT_WORK_FACTOR
);
registerAuthDto
.
password
=
await
bcrypt
.
hash
(
...
...
@@ -50,16 +52,22 @@ export class AuthService {
const
isMatch
=
await
bcrypt
.
compare
(
password
,
user
?.
password
||
''
);
if
(
!
isMatch
)
throw
new
UnauthorizedException
(
'Неверный логин или пароль'
);
const
{
accessToken
}
=
await
this
.
generateToken
({
username
,
password
});
const
{
accessToken
}
=
await
this
.
generateToken
({
username
,
role
:
user
.
role
||
''
,
});
return
{
accessToken
,
id
:
user
.
id
,
username
:
user
.
username
};
}
async
signToken
(
registerAuthDto
:
RegisterDto
,
expiresIn
:
string
)
{
async
signToken
(
{
username
,
role
}:
{
username
:
string
;
role
:
string
},
expiresIn
:
string
,
)
{
return
await
this
.
jwtService
.
signAsync
(
{
username
:
registerAuthDto
.
username
,
password
:
registerAuthDto
.
password
,
username
,
role
,
},
{
secret
:
'test'
,
...
...
@@ -82,9 +90,9 @@ export class AuthService {
return
null
;
}
async
generateToken
(
registerAuthDto
:
RegisterDto
)
{
const
accessToken
=
await
this
.
signToken
(
registerAuthDto
,
'30m'
);
const
refreshToken
=
await
this
.
signToken
(
registerAuthDto
,
'7d'
);
async
generateToken
(
{
username
,
role
}:
{
username
:
string
;
role
:
string
}
)
{
const
accessToken
=
await
this
.
signToken
(
{
username
,
role
}
,
'30m'
);
const
refreshToken
=
await
this
.
signToken
(
{
username
,
role
}
,
'7d'
);
return
{
accessToken
,
refreshToken
,
...
...
server/src/auth/dto/register.dto.ts
View file @
42a92e0e
...
...
@@ -8,4 +8,7 @@ export class RegisterDto {
@
IsString
()
@
IsNotEmpty
()
password
:
string
;
@
IsString
()
role
:
string
;
}
server/src/common/constants/roles.ts
0 → 100644
View file @
42a92e0e
export
enum
Role
{
admin
=
'admin'
,
user
=
'user'
,
}
server/src/common/decorators/roles.decarator.ts
0 → 100644
View file @
42a92e0e
import
{
SetMetadata
}
from
'@nestjs/common'
;
export
const
ROLES_KEY
=
'roles'
;
export
const
Roles
=
(...
roles
:
string
[])
=>
SetMetadata
(
ROLES_KEY
,
roles
);
server/src/common/guards/jwt-auth.guar
f
.ts
→
server/src/common/guards/jwt-auth.guar
d
.ts
View file @
42a92e0e
File moved
server/src/common/guards/roles.guard.ts
0 → 100644
View file @
42a92e0e
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import
{
CanActivate
,
ExecutionContext
,
ForbiddenException
,
Injectable
,
UnauthorizedException
,
}
from
'@nestjs/common'
;
import
{
Reflector
}
from
'@nestjs/core'
;
import
{
JwtService
}
from
'@nestjs/jwt'
;
import
{
ROLES_KEY
}
from
'../decorators/roles.decarator'
;
@
Injectable
()
export
class
RolesGuard
implements
CanActivate
{
constructor
(
private
reflector
:
Reflector
,
private
jwtService
:
JwtService
,
)
{}
canActivate
(
context
:
ExecutionContext
):
boolean
{
const
requiredRoles
=
this
.
reflector
.
getAllAndOverride
<
string
[]
>
(
ROLES_KEY
,
[
context
.
getHandler
(),
context
.
getClass
()],
);
if
(
!
requiredRoles
)
return
true
;
const
request
=
context
.
switchToHttp
().
getRequest
();
const
authHeader
=
request
.
headers
[
'authorization'
];
if
(
!
authHeader
||
!
authHeader
.
startsWith
(
'Bearer '
))
{
throw
new
UnauthorizedException
(
'Требуется токен'
);
}
const
token
=
authHeader
.
split
(
' '
)[
1
];
const
user
=
this
.
jwtService
.
verify
(
token
);
request
.
user
=
user
;
if
(
!
requiredRoles
.
includes
(
user
.
role
))
{
throw
new
ForbiddenException
(
'Недостаточно прав'
);
}
return
true
;
}
}
server/src/common/strategy/jwt.strategy.ts
View file @
42a92e0e
import
{
ExtractJwt
,
Strategy
}
from
'passport-jwt'
;
import
{
PassportStrategy
}
from
'@nestjs/passport'
;
import
{
Injectable
}
from
'@nestjs/common'
;
import
{
PassportStrategy
}
from
'@nestjs/passport'
;
import
{
ExtractJwt
,
Strategy
}
from
'passport-jwt'
;
@
Injectable
()
export
class
JwtStrategy
extends
PassportStrategy
(
Strategy
)
{
...
...
@@ -12,7 +12,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
});
}
validate
(
payload
:
{
username
:
string
})
{
return
{
username
:
payload
.
username
};
validate
(
payload
:
{
username
:
string
;
role
:
string
})
{
return
{
username
:
payload
.
username
,
role
:
payload
.
role
};
}
}
server/src/product/product.controller.ts
View file @
42a92e0e
import
{
Body
,
Controller
,
Delete
,
Get
,
Post
,
Body
,
Param
,
Delete
,
Post
,
UploadedFile
,
UseGuards
,
UseInterceptors
,
UploadedFile
,
}
from
'@nestjs/common'
;
import
{
ProductService
}
from
'./product.service'
;
import
{
CreateProductDto
}
from
'./dto/create-product.dto'
;
import
{
JwtAuthGuard
}
from
'src/common/guards/jwt-auth.guarf'
;
import
{
FileInterceptor
}
from
'@nestjs/platform-express'
;
import
{
Roles
}
from
'src/common/decorators/roles.decarator'
;
import
{
JwtAuthGuard
}
from
'src/common/guards/jwt-auth.guard'
;
import
{
CreateProductDto
}
from
'./dto/create-product.dto'
;
import
{
ProductService
}
from
'./product.service'
;
@
Controller
(
'product'
)
export
class
ProductController
{
...
...
@@ -28,6 +29,7 @@ export class ProductController {
}
@
UseGuards
(
JwtAuthGuard
)
@
Roles
(
'user'
)
@
Get
()
findAll
()
{
return
this
.
productService
.
findAll
();
...
...
server/src/product/product.module.ts
View file @
42a92e0e
import
{
Module
}
from
'@nestjs/common'
;
import
{
ProductService
}
from
'./product.service'
;
import
{
ProductController
}
from
'./product.controller'
;
import
{
Product
}
from
'./entities/product.entity'
;
import
{
TypeOrmModule
}
from
'@nestjs/typeorm'
;
import
{
Category
}
from
'src/category/entities/category.entity'
;
import
{
MulterModule
}
from
'@nestjs/platform-express'
;
import
{
TypeOrmModule
}
from
'@nestjs/typeorm'
;
import
{
diskStorage
}
from
'multer'
;
import
{
extname
,
join
}
from
'path'
;
import
{
Category
}
from
'src/category/entities/category.entity'
;
import
{
Product
}
from
'./entities/product.entity'
;
import
{
ProductController
}
from
'./product.controller'
;
import
{
ProductService
}
from
'./product.service'
;
@
Module
({
imports
:
[
...
...
server/src/seed/seed.module.ts
View file @
42a92e0e
import
{
Module
}
from
'@nestjs/common'
;
import
{
SeedService
}
from
'./seed.service'
;
import
{
SeedController
}
from
'./seed.controller'
;
import
{
ProductModule
}
from
'src/product/product.module'
;
import
{
AuthModule
}
from
'src/auth/auth.module'
;
import
{
CategoryModule
}
from
'src/category/category.module'
;
import
{
ProductModule
}
from
'src/product/product.module'
;
import
{
SeedController
}
from
'./seed.controller'
;
import
{
SeedService
}
from
'./seed.service'
;
@
Module
({
imports
:
[
ProductModule
,
CategoryModule
],
imports
:
[
ProductModule
,
CategoryModule
,
AuthModule
],
controllers
:
[
SeedController
],
providers
:
[
SeedService
],
})
...
...
server/src/seed/seed.service.ts
View file @
42a92e0e
import
{
faker
}
from
'@faker-js/faker'
;
import
{
Injectable
}
from
'@nestjs/common'
;
import
{
AuthService
}
from
'src/auth/auth.service'
;
import
{
CategoryService
}
from
'src/category/category.service'
;
import
{
ProductService
}
from
'src/product/product.service'
;
import
{
faker
}
from
'@faker-js/faker'
;
import
{
Category
}
from
'src/category/entities/category.entity'
;
import
{
Role
}
from
'src/common/constants/roles'
;
import
{
Product
}
from
'src/product/entities/product.entity'
;
import
{
ProductService
}
from
'src/product/product.service'
;
@
Injectable
()
export
class
SeedService
{
constructor
(
private
productService
:
ProductService
,
private
categoryService
:
CategoryService
,
private
authService
:
AuthService
,
)
{}
async
create
()
{
...
...
@@ -19,6 +22,18 @@ export class SeedService {
const
categories
:
Category
[]
=
[];
const
products
:
Product
[]
=
[];
await
this
.
authService
.
register
({
username
:
'admin'
,
role
:
Role
.
admin
,
password
:
'123456'
,
});
await
this
.
authService
.
register
({
username
:
'user'
,
role
:
Role
.
user
,
password
:
'123456'
,
});
for
(
let
i
=
0
;
i
<
50
;
i
++
)
{
const
name
=
faker
.
food
.
dish
();
const
description
=
faker
.
food
.
description
();
...
...
server/src/user/dto/create-user.dto.ts
View file @
42a92e0e
...
...
@@ -11,4 +11,7 @@ export class CreateUserDto {
@
IsString
()
refreshToken
:
string
;
@
IsString
()
role
:
string
;
}
server/src/user/entities/user.entity.ts
View file @
42a92e0e
import
{
Role
}
from
'src/common/constants/roles'
;
import
{
Column
,
Entity
,
PrimaryGeneratedColumn
}
from
'typeorm'
;
@
Entity
()
...
...
@@ -13,4 +14,7 @@ export class User {
@
Column
({
nullable
:
true
})
refreshToken
?:
string
;
@
Column
({
nullable
:
true
,
enum
:
Role
})
role
:
string
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment