diff --git a/TempLate/index.html b/TempLate/index.html index 7a4b4866..a979603b 100644 --- a/TempLate/index.html +++ b/TempLate/index.html @@ -5,7 +5,7 @@ 银河锋锐(GVSDS) - + diff --git a/backup/www/index.html b/backup/www/index.html index 023ef771..7a4b4866 100644 --- a/backup/www/index.html +++ b/backup/www/index.html @@ -5,8 +5,8 @@ 银河锋锐(GVSDS) - - + +
diff --git a/gvsds/apps/core/migrations/0004_add_default_role_uuid.py b/gvsds/apps/core/migrations/0004_add_default_role_uuid.py new file mode 100644 index 00000000..f6ebab50 --- /dev/null +++ b/gvsds/apps/core/migrations/0004_add_default_role_uuid.py @@ -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'), + ), + ] \ No newline at end of file diff --git a/gvsds/apps/core/models.py b/gvsds/apps/core/models.py index 1d979d08..5c192517 100644 --- a/gvsds/apps/core/models.py +++ b/gvsds/apps/core/models.py @@ -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() diff --git a/gvsds/apps/ugm/serializers.py b/gvsds/apps/ugm/serializers.py index 41c9bc18..cf5304fe 100644 --- a/gvsds/apps/ugm/serializers.py +++ b/gvsds/apps/ugm/serializers.py @@ -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) diff --git a/gvsds/apps/ugm/urls.py b/gvsds/apps/ugm/urls.py index 0510c92e..b76d0be5 100644 --- a/gvsds/apps/ugm/urls.py +++ b/gvsds/apps/ugm/urls.py @@ -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'), diff --git a/gvsds/apps/ugm/views.py b/gvsds/apps/ugm/views.py index 6e3c0909..89c5503a 100644 --- a/gvsds/apps/ugm/views.py +++ b/gvsds/apps/ugm/views.py @@ -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}})