Приступим к установке прав доступа для конечных точек товаров. В файле routers/products.py мы добавили следующие пути:
all_products- Метод получения всех товаровcreate_product- Метод создания товараproduct_by_category- Метод получения товаров определенной категорииproduct_detail- Метод получения детальной информации о товареupdate_product- Метод изменения товараdelete_product- Метод удаления товара
Начнем реализацию, в файле routers/products.py изменим конечную точку создания товаров:
@router.post('/create')
async def create_product(db: Annotated[AsyncSession, Depends(get_db)], create_product: CreateProduct,
get_user: Annotated[dict, Depends(get_current_user)]):
if get_user.get('is_supplier') or get_user.get('is_admin'):
await db.execute(insert(Product).values(name=create_product.name,
description=create_product.description,
price=create_product.price,
image_url=create_product.image_url,
stock=create_product.stock,
category_id=create_product.category,
rating=0.0,
slug=slugify(create_product.name),
supplier_id=get_user.get('id')))
await db.commit()
return {
'status_code': status.HTTP_201_CREATED,
'transaction': 'Successful'
}
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='You are not authorized to use this method'
)
Первым делом мы добавили условие, кто может создавать товары, get_user.get('is_supplier') или get_user.get('is_admin'). Мы получаем данные параметры из JWT токена, чтобы создавать товар мог, только пользователь со статусом продавец или администратор. Также обратите внимание, что теперь при создании товара, мы заполняем поле продавца товара supplier_id=get_user.get('id'), чтобы закрепить за продавцем данный товар.
В ином случае мы вызываем 401 ошибку с текстом "You are not authorized to use this method"
По аналогии изменим конечные точки отвечающие за изменение товаров:
@router.put('/detail/{product_slug}')
async def update_product(db: Annotated[AsyncSession, Depends(get_db)], product_slug: str,
update_product_model: CreateProduct, get_user: Annotated[dict, Depends(get_current_user)]):
product_update = await db.scalar(select(Product).where(Product.slug == product_slug))
if product_update is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail='There is no product found'
)
if get_user.get('is_supplier') or get_user.get('is_admin'):
if get_user.get('id') == product_update.supplier_id or get_user.get('is_admin'):
await db.execute(
update(Product).where(Product.slug == product_slug)
.values(name=update_product_model.name,
description=update_product_model.description,
price=update_product_model.price,
image_url=update_product_model.image_url,
stock=update_product_model.stock,
category_id=update_product_model.category,
slug=slugify(update_product_model.name)))
await db.commit()
return {
'status_code': status.HTTP_200_OK,
'transaction': 'Product update is successful'
}
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='You are not authorized to use this method'
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='You are not authorized to use this method'
)
Но в данной конечной точке мы проверяем условие, кто отправляет запрос, продавец или администратор.
Далее в строке if get_user.get('id') == product_update.supplier_id or get_user.get('is_admin') мы проверяем, у того кто обратился, id равен id продавцу товара или это администратор.
По аналогии поступим и для конечной точки удаления товаров.
@router.delete('/delete')
async def delete_product(db: Annotated[AsyncSession, Depends(get_db)], product_id: int,
get_user: Annotated[dict, Depends(get_current_user)]):
product_delete = await db.scalar(select(Product).where(Product.id == product_id))
if product_delete is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail='There is no product found'
)
if get_user.get('is_supplier') or get_user.get('is_admin'):
if get_user.get('id') == product_delete.supplier_id or get_user.get('is_admin'):
await db.execute(update(Product).where(Product.id == product_id).values(is_active=False))
await db.commit()
return {
'status_code': status.HTTP_200_OK,
'transaction': 'Product delete is successful'
}
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='You are not authorized to use this method'
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='You are not authorized to use this method'
)
Заключение.
Безопасность любых приложений всегда является главным приоритетом при создании качественного проекта. FastAPI — это одна из платформ API, которая имеет встроенную поддержку многих популярных процессов аутентификации, от базовой до спецификации OpenID Connect. Он полностью поддерживает все эффективные схемы аутентификации OAuth2 и даже доступен для дальнейшей настройки API безопасности.
В нашем случае метод get_current_user() должен быть внедрен в каждую реализацию сервиса, чтобы ограничить доступ пользователей. Он не только проверит учетные данные, но и выполнит декодирование полезной нагрузки JWT.