完善权限体系

新增授权接口
This commit is contained in:
晓丰 2025-04-15 16:01:11 +08:00
parent b6a0abd9ee
commit ae6db6ec44
4 changed files with 104 additions and 3 deletions

74
accounts/api/authorize.py Normal file
View File

@ -0,0 +1,74 @@
from ninja import Router, Schema, Query
from pydantic import Field
from typing import List
from django.shortcuts import get_object_or_404
from accounts.models import User
from websites.models import Website
from utils.auth import jwt_auth
from utils.permissions import manager_required
router = Router(tags=["授权管理"])
class AuthorizeIn(Schema):
user_id: int = Field(..., description="被授权的用户ID")
website_ids: List[int] = Field(..., description="要授权的网站ID列表")
@router.post("/authorize", auth=jwt_auth)
@manager_required
def authorize_user(request, data: AuthorizeIn):
manager = request.user
target_user = get_object_or_404(User, id=data.user_id)
if target_user.role != "user":
return {"success": False, "message": "只能授权给普通用户"}
managed_ids = set(manager.managed_websites.values_list("id", flat=True))
for wid in data.website_ids:
if wid not in managed_ids:
return {"success": False, "message": f"无权授权网站ID{wid}"}
target_user.authorized_websites.add(*data.website_ids)
return {
"success": True,
"message": f"已授权 {target_user.username} 访问 {len(data.website_ids)} 个网站",
}
@router.get("/authorized-sites", auth=jwt_auth)
@manager_required
def get_user_authorized_sites(request, user_id: int = Query(...)):
target_user = get_object_or_404(User, id=user_id)
if target_user.role != "user":
return {"success": False, "message": "只能查看普通用户的授权信息"}
sites = target_user.authorized_websites.all().values("id", "name", "db_alias")
return {
"success": True,
"user": target_user.username,
"authorized_websites": list(sites)
}
@router.post("/revoke", auth=jwt_auth)
@manager_required
def revoke_authorization(request, data: AuthorizeIn):
manager = request.user
target_user = get_object_or_404(User, id=data.user_id)
if target_user.role != "user":
return {"success": False, "message": "只能撤销普通用户的授权"}
managed_ids = set(manager.managed_websites.values_list("id", flat=True))
for wid in data.website_ids:
if wid not in managed_ids:
return {"success": False, "message": f"无权撤销网站ID{wid}"}
target_user.authorized_websites.remove(*data.website_ids)
return {
"success": True,
"message": f"已撤销 {target_user.username}{len(data.website_ids)} 个授权网站"
}

View File

@ -1,6 +1,6 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
from websites.models import Website
class User(AbstractUser):
ROLE_CHOICES = [
@ -9,7 +9,18 @@ class User(AbstractUser):
('user', '普通用户'),
]
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user', help_text="用户角色")
managed_websites = models.ManyToManyField(
Website,
blank=True,
related_name="managers",
help_text="分管理可管理的网站"
)
authorized_websites = models.ManyToManyField(
Website,
blank=True,
related_name="authorized_users",
help_text="普通用户被授权可访问的网站"
)
def is_admin(self):
return self.role == 'admin'

2
api.py
View File

@ -2,8 +2,10 @@ from ninja import NinjaAPI
from resumes.api.views import router as resume_router
from accounts.api.auth import auth_router
from accounts.api.user import user_router
from accounts.api.authorize import router
api = NinjaAPI(title="简历管理 API")
api.add_router("/resumes/", resume_router)
api.add_router("/auth", auth_router)
api.add_router("/users", user_router)
api.add_router("/authorize", router)

View File

@ -1,11 +1,16 @@
from ninja import Router, Query
from accounts.models import User
from resumes.models import ResumeBasic
from resumes.api.schemas import ResumeBasicOut, PaginatedResumes
from typing import Optional
from utils.auth import jwt_auth
from utils.permissions import login_required
router = Router(tags=["简历"])
@router.get("/", response=PaginatedResumes)
@router.get("/", response=PaginatedResumes, auth=jwt_auth)
@login_required
def list_resumes(
request,
job_status: Optional[str] = Query(None),
@ -16,8 +21,16 @@ def list_resumes(
limit: int = 10,
offset: int = 0
):
user = request.user
qs = ResumeBasic.objects.all()
if user.is_admin():
pass # 管理员访问全部
elif user.is_manager():
qs = qs.filter(source_id__in=user.managed_websites.values_list("id", flat=True))
elif user.is_user():
qs = qs.filter(source_id__in=user.authorized_websites.values_list("id", flat=True))
if job_status:
qs = qs.filter(job_status=job_status)
if age:
@ -28,6 +41,7 @@ def list_resumes(
qs = qs.filter(source_id=source_id)
if keyword:
qs = qs.filter(crawl_keywords__icontains=keyword)
total = qs.count()
results = qs[offset:offset + limit]