Skip to content

Commit 115fe9c

Browse files
Merge pull request #5 from Cinnamoon-dev/feat/permissions
feat: permissions added to controllers
2 parents 30b9195 + bb18eab commit 115fe9c

8 files changed

Lines changed: 113 additions & 16 deletions

File tree

src/controllers/_helpers.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import jwt
21
from typing import Annotated, Any
32
from fastapi import Depends, HTTPException
43
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
54

65
from src.services.userService import UserService
6+
from src.infra.database.database import PgDatabase
77
from src.infra.security.hashing import ALGORITHM, JWT_ACCESS_SECRET_KEY, decode_token
88

99
oauth2_bearer = OAuth2PasswordBearer(tokenUrl="auth/login")
@@ -22,4 +22,27 @@ def get_current_user(token: token_dependency) -> dict[str, Any]:
2222
return user
2323

2424
user_dependency = Annotated[dict[str, Any], Depends(get_current_user)]
25-
form_auth_dependency = Annotated[OAuth2PasswordRequestForm, Depends()]
25+
form_auth_dependency = Annotated[OAuth2PasswordRequestForm, Depends()]
26+
27+
class PermissionChecker():
28+
def __init__(self, required_permission: str):
29+
self.required_permission = required_permission
30+
31+
def __call__(self, user: user_dependency):
32+
controller, action = self.required_permission.split("-")
33+
user_type_id = user["tipo_usuario_id"]
34+
35+
query = """
36+
SELECT regras.acao, regras.permitir, controllers.nome, tipo_usuario.nome
37+
FROM regras
38+
JOIN controllers ON controllers.id = regras.controller_id
39+
JOIN tipo_usuario ON tipo_usuario.id = regras.tipo_usuario_id
40+
WHERE tipo_usuario.id = %s AND regras.permitir = True AND controllers.nome = %s AND regras.acao = %s
41+
"""
42+
43+
with PgDatabase() as db:
44+
db.cursor.execute(query, (user_type_id, controller, action))
45+
row = db.cursor.fetchone()
46+
47+
if row is None:
48+
raise HTTPException(status_code=403, detail={"message": "Usuário não autorizado", "error": True})

src/controllers/userController.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
from fastapi import APIRouter, Request
1+
from fastapi import APIRouter, Depends, Request
22

3+
from ._helpers import PermissionChecker
34
from src.services.userService import UserService
45
from src.schemas.userSchema import UserAddSchema, UserEditSchema
56

@@ -12,22 +13,36 @@ def user_all(
1213
page: int = 1,
1314
rows_per_page: int = 10,
1415
sort_by: str | None = None,
15-
show_fk_id: int | None = 1
16+
show_fk_id: int | None = 1,
17+
perms = Depends(PermissionChecker("usuario-all"))
1618
):
1719
return UserService().all(request.query_params)
1820

1921
@router.get("/{user_id:int}")
20-
def user_view(user_id: int):
22+
def user_view(
23+
user_id: int,
24+
perms = Depends(PermissionChecker("usuario-view"))
25+
):
2126
return UserService().view(user_id)
2227

2328
@router.post("/")
24-
def user_add(user: UserAddSchema):
29+
def user_add(
30+
user: UserAddSchema,
31+
perms = Depends(PermissionChecker("usuario-add"))
32+
):
2533
return UserService().add(user)
2634

2735
@router.put("/{user_id:int}")
28-
def user_edit(user_id: int, user: UserEditSchema):
36+
def user_edit(
37+
user_id: int,
38+
user: UserEditSchema,
39+
perms = Depends(PermissionChecker("usuario-edit"))
40+
):
2941
return UserService().edit(user_id, user)
3042

3143
@router.delete("/{user_id:int}")
32-
def user_delete(user_id: int):
44+
def user_delete(
45+
user_id: int,
46+
perms = Depends(PermissionChecker("usuario-delete"))
47+
):
3348
return UserService().delete(user_id)
Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
from fastapi import APIRouter, Request
1+
from fastapi import APIRouter, Depends, Request
22

3+
from ._helpers import PermissionChecker
34
from src.schemas.userTypeSchema import UserTypeSchema
45
from src.services.userTypeService import UserTypeService
56

@@ -10,26 +11,40 @@ def user_type_all(
1011
request: Request,
1112
page: int = 1,
1213
rows_per_page: int = 10,
13-
sort_by: str | None = None
14+
sort_by: str | None = None,
15+
perms = Depends(PermissionChecker("tipo_usuario-all"))
1416
):
1517
return UserTypeService().all(request.query_params)
1618

1719
@router.get("/{user_type_id:int}")
18-
def user_type_view(user_type_id: int):
20+
def user_type_view(
21+
user_type_id: int,
22+
perms = Depends(PermissionChecker("tipo_usuario-view"))
23+
):
1924
response = UserTypeService().view(user_type_id)
2025
return response
2126

2227
@router.post("/")
23-
def user_type_add(user_type: UserTypeSchema):
28+
def user_type_add(
29+
user_type: UserTypeSchema,
30+
perms = Depends(PermissionChecker("tipo_usuario-add"))
31+
):
2432
response = UserTypeService().add(user_type)
2533
return response
2634

2735
@router.put("/{user_type_id:int}")
28-
def user_type_edit(user_type_id: int, user_type: UserTypeSchema):
36+
def user_type_edit(
37+
user_type_id: int,
38+
user_type: UserTypeSchema,
39+
perms = Depends(PermissionChecker("tipo_usuario-edit"))
40+
):
2941
response = UserTypeService().edit(user_type_id, user_type)
3042
return response
3143

3244
@router.delete("/{user_type_id:int}")
33-
def user_type_delete(user_type_id: int):
45+
def user_type_delete(
46+
user_type_id: int,
47+
perms = Depends(PermissionChecker("tipo_usuario-delete"))
48+
):
3449
response = UserTypeService().delete(user_type_id)
3550
return response

src/infra/database/populate.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def insert(filePath: str) -> None:
1919
db.connection.commit()
2020

2121
insert("/scripts/tables.sql")
22+
insert("/scripts/rules.sql")
2223

2324

2425
if __name__ == "__main__":
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-- Tipo Usuário
2+
INSERT INTO tipo_usuario (id, nome) VALUES (1, 'admin');
3+
4+
-- Usuário
5+
-- senha: 1234
6+
INSERT INTO usuario (id, email, senha, tipo_usuario_id) VALUES (1, "admin@email.com", "$6$xvhoMyeu7TlurX6Z$.j4NQGAvbEzu3IKSJAWU8IzTqAGVW8RZ2sUWmJSzJY2QR0VJhm26rOC/0.7UXT3c8YrwoS3y4pUdbWJV7GEZG1", 1)
7+
8+
-- Controllers
9+
INSERT INTO controllers (id, nome) VALUES (1, 'usuario');
10+
INSERT INTO controllers (id, nome) VALUES (2, 'tipo_usuario');
11+
12+
-- Admin Rules
13+
-- admin + usuario controller
14+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (1, 1, 1, 'all', True);
15+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (2, 1, 1, 'view', True);
16+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (3, 1, 1, 'add', True);
17+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (4, 1, 1, 'edit', True);
18+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (5, 1, 1, 'delete', True);
19+
20+
-- admin + tipo_usuario controller
21+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (6, 2, 1, 'all', True);
22+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (7, 2, 1, 'view', True);
23+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (8, 2, 1, 'add', True);
24+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (9, 2, 1, 'edit', True);
25+
INSERT INTO regras (id, controller_id, tipo_usuario_id, acao, permitir) VALUES (10, 2, 1, 'delete', True);

src/infra/database/scripts/tables.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@ CREATE TABLE IF NOT EXISTS usuario (
99
senha VARCHAR(200) NOT NULL,
1010
tipo_usuario_id INTEGER NOT NULL,
1111

12+
CONSTRAINT fk_tipo_usuario FOREIGN KEY (tipo_usuario_id)
13+
REFERENCES tipo_usuario (id)
14+
);
15+
16+
CREATE TABLE IF NOT EXISTS controllers (
17+
id SERIAL PRIMARY KEY,
18+
nome VARCHAR(50) UNIQUE NOT NULL
19+
);
20+
21+
CREATE TABLE IF NOT EXISTS regras (
22+
id SERIAL PRIMARY KEY,
23+
acao VARCHAR(50) NOT NULL,
24+
permitir BOOLEAN NOT NULL,
25+
controller_id INTEGER NOT NULL,
26+
tipo_usuario_id INTEGER NOT NULL,
27+
28+
CONSTRAINT fk_controller FOREIGN KEY (controller_id)
29+
REFERENCES controllers (id),
1230
CONSTRAINT fk_tipo_usuario FOREIGN KEY (tipo_usuario_id)
1331
REFERENCES tipo_usuario (id)
1432
);

src/services/userService.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def __init__(self) -> None:
1717
try:
1818
self.all_columns = reduce(lambda acc, elem: acc + ", " + str(elem), self.columns)
1919
except Exception:
20-
self.all_columns = ""
20+
self.all_columns = "*"
2121

2222
def all(self, query_params: QueryParams) -> dict[str, Any]:
2323
show_fk_id = bool(int(query_params.get("show_fk_id", 1)))

src/services/userTypeService.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def __init__(self) -> None:
1919
try:
2020
self.all_columns = reduce(lambda acc, elem: acc + ", " + str(elem), self.columns)
2121
except Exception:
22-
self.all_columns = ""
22+
self.all_columns = "*"
2323

2424
def all(self, query_params: QueryParams) -> dict[str, Any]:
2525
query = f"SELECT {self.all_columns} FROM {self.table}"

0 commit comments

Comments
 (0)