feat(auth): User.DefaultRoleUUID 默认登录角色(登录自动激活)
- core.User 新增 DefaultRoleUUID(UUIDField 可空)+ 手写迁移 0004 - _SetCurrentRoleCookie 登录/注册优先激活默认角色(须持有且启用),否则回退首个角色 - GetUserRoles 返回 IsDefault 标记;新增 SetDefaultRole 接口(空 RoleUUID=清除默认)
This commit is contained in:
1 parent
b1ccb9e0e1
commit
ec43c4dfe6
7 files changed
+61
-8
No files matched your search
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>银河锋锐(GVSDS)</title>
|
||||
<link rel="icon" href="https://hb.cdn.gvsds.com/assets/icon/ICON.png">
|
||||
<script type="module" crossorigin src="/GVSite/index-CK-5nual.js"></script>
|
||||
<script type="module" crossorigin src="/GVSite/index-DhQua3qJ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/GVSite/index-DRWk7H-y.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>银河锋锐(GVSDS)</title>
|
||||
<link rel="icon" href="https://hb.cdn.gvsds.com/assets/icon/ICON.png">
|
||||
<script type="module" crossorigin src="/GVSite/index-tyrWQVZX.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/GVSite/index-BY1hqLY-.css">
|
||||
<script type="module" crossorigin src="/GVSite/index-CK-5nual.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/GVSite/index-DRWk7H-y.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
from django.db import migrations
|
||||
|
||||
import gvsds.apps.core.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0003_remove_ephemeraltoken'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='DefaultRoleUUID',
|
||||
field=gvsds.apps.core.models.UUIDField(blank=True, null=True, verbose_name='默认角色UUID'),
|
||||
),
|
||||
]
|
||||
@@ -137,6 +137,8 @@ class User(QModel):
|
||||
UserLastLoginDate = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='最后登录')
|
||||
IsStaff = models.BooleanField(default=False, verbose_name='是否员工')
|
||||
IsSuperuser = models.BooleanField(default=False, verbose_name='是否超级用户')
|
||||
# 默认登录角色:登录/注册后自动激活的角色(空 = 取用户首个角色)
|
||||
DefaultRoleUUID = UUIDField(null=True, blank=True, verbose_name='默认角色UUID')
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ class SwitchRoleSerializer(PascalCaseSerializer):
|
||||
RoleUUID = serializers.CharField()
|
||||
|
||||
|
||||
class SetDefaultRoleSerializer(PascalCaseSerializer):
|
||||
RoleUUID = serializers.CharField(required=False, allow_blank=True, default='')
|
||||
|
||||
|
||||
class ModifyPasswordSerializer(PascalCaseSerializer):
|
||||
OldPassword = serializers.CharField(max_length=256, required=False)
|
||||
NewPassword = serializers.CharField(max_length=256, required=False)
|
||||
|
||||
@@ -6,6 +6,7 @@ urlpatterns = [
|
||||
path('register/', views.RegisterView.as_view(), name='register'),
|
||||
path('verify-2fa/', views.Verify2FAView.as_view(), name='verify_2fa'),
|
||||
path('switch-role/', views.SwitchRoleView.as_view(), name='switch_role'),
|
||||
path('set-default-role/', views.SetDefaultRoleView.as_view(), name='set_default_role'),
|
||||
path('user-roles/', views.GetUserRolesView.as_view(), name='user_roles'),
|
||||
path('user-info/', views.GetUserInfoView.as_view(), name='user_info'),
|
||||
path('user-avatar/', views.GetUserAvatarView.as_view(), name='user_avatar'),
|
||||
|
||||
+33
-5
@@ -14,7 +14,7 @@ from gvsdsdk.model_utils import UUIDObj
|
||||
from gvsds.app_config import getlist as _app_getlist
|
||||
from .serializers import (
|
||||
LoginSerializer, RegisterSerializer, Verify2FASerializer,
|
||||
SwitchRoleSerializer, ModifyPasswordSerializer,
|
||||
SwitchRoleSerializer, ModifyPasswordSerializer, SetDefaultRoleSerializer,
|
||||
)
|
||||
|
||||
_ALLOWED_DOMAINS = set(_app_getlist('domain', 'KNOWN_DOMAINS', fallback=[
|
||||
@@ -82,13 +82,22 @@ def _ClearJwtCookies(response):
|
||||
|
||||
|
||||
def _SetCurrentRoleCookie(response, user):
|
||||
"""查询用户首个角色并设置 CurrentRoleUUID cookie"""
|
||||
"""设置 CurrentRoleUUID cookie:优先用户默认角色(DefaultRoleUUID,须持有且启用),否则取首个角色"""
|
||||
from gvsdsdk.auth.managers import RoleManager
|
||||
first_role = RoleManager.GetRolesForUser(user.UserUUID).first()
|
||||
if first_role and first_role.RoleUUID:
|
||||
role_uuid = ''
|
||||
default_uuid = getattr(user, 'DefaultRoleUUID', None)
|
||||
if default_uuid:
|
||||
role = RoleManager.GetRoleByUUID(default_uuid)
|
||||
if role and role.RoleStatus == 1 and RoleManager.HasRole(user.UserUUID, default_uuid):
|
||||
role_uuid = UUIDObj(default_uuid).str
|
||||
if not role_uuid:
|
||||
first_role = RoleManager.GetRolesForUser(user.UserUUID).first()
|
||||
if first_role and first_role.RoleUUID:
|
||||
role_uuid = UUIDObj(first_role.RoleUUID).str
|
||||
if role_uuid:
|
||||
max_age = int(settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'].total_seconds())
|
||||
response.set_cookie(
|
||||
'CurrentRoleUUID', UUIDObj(first_role.RoleUUID).str,
|
||||
'CurrentRoleUUID', role_uuid,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN, max_age=max_age,
|
||||
secure=True, httponly=False, samesite='None',
|
||||
)
|
||||
@@ -273,6 +282,22 @@ class SwitchRoleView(APIView):
|
||||
return response
|
||||
|
||||
|
||||
class SetDefaultRoleView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
data = request.data.copy()
|
||||
serializer = SetDefaultRoleSerializer(data=data)
|
||||
serializer.IsValid(raise_exception=True)
|
||||
role_uuid = serializer.ValidatedData['RoleUUID'].strip()
|
||||
from gvsdsdk.auth.managers import RoleManager
|
||||
if role_uuid and not RoleManager.HasRole(request.user.UserUUID, role_uuid):
|
||||
return Response({'code': 1, 'msg': '无权设置该角色为默认'}, status=403)
|
||||
request.user.DefaultRoleUUID = UUIDObj(role_uuid).bytes if role_uuid else None
|
||||
request.user.save(update_fields=['DefaultRoleUUID'])
|
||||
return Response({'code': 0, 'msg': '默认登录角色已更新'})
|
||||
|
||||
|
||||
class GetUserRolesView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
@@ -281,6 +306,8 @@ class GetUserRolesView(APIView):
|
||||
# 角色不绑定公司/部门,通过 UserRole.CompanyUUID 获取关联公司
|
||||
user_roles = RoleManager.GetUserRoleDetails(request.user.UserUUID)
|
||||
current_role_uuid = request.COOKIES.get('CurrentRoleUUID', '')
|
||||
default_uuid = getattr(request.user, 'DefaultRoleUUID', None)
|
||||
default_role_uuid = UUIDObj(default_uuid).str if default_uuid else ''
|
||||
roles = []
|
||||
for ur in user_roles:
|
||||
# 两步查询:UserRole.RoleUUID 是 UUIDField,需先查 Role 表
|
||||
@@ -309,6 +336,7 @@ class GetUserRolesView(APIView):
|
||||
'CompanyShort': company_short,
|
||||
'CompanyUUID': company_uuid_str,
|
||||
'active': UUIDObj(role.RoleUUID).str == current_role_uuid,
|
||||
'IsDefault': UUIDObj(role.RoleUUID).str == default_role_uuid,
|
||||
})
|
||||
return Response({'code': 0, 'data': {'roles': roles}})
|
||||
|
||||
|
||||
Reference in new issue
Block a user