import base64 import os from django.conf import settings from django.contrib.auth import authenticate from django.db.utils import OperationalError, ProgrammingError from gmssl import sm4 from rest_framework.response import Response from rest_framework.views import APIView from rest_framework_simplejwt.tokens import RefreshToken class UserLoginView(APIView): def post(self, request, *args, **kwargs): if os.environ.get("DJANGO_LOGIN_BREAKPOINT", "").strip().lower() in { "1", "true", "yes", "y", "on", }: breakpoint() try: username = request.data.get("username") encrypted_password = request.data.get("password") if not username or not encrypted_password: return Response({"code": "1", "error": "用户名或密码不能为空"}) private_key = getattr(settings, "SM4_PRIVATE_KEY", getattr(settings, "private_key", "")) if not private_key: return Response({"code": "1", "error": "缺少加密密钥"}) try: password = self.decrypt_password(encrypted_password, private_key) except Exception: return Response({"code": "1", "error": "密码解密失败"}) user = authenticate(request, username=username, password=password) if user is not None: refresh = RefreshToken.for_user(user) user_groups = [group.id for group in user.groups.all()] return Response( { "access_token": str(refresh.access_token), "refresh_token": str(refresh), "user_id": user.id, "username": user.username, "email": user.email, "groups": user_groups, "is_superuser": user.is_superuser, } ) return Response({"code": "1", "error": "用户名或密码不正确,请检查并重试!"}) except (OperationalError, ProgrammingError) as e: payload = {"code": "1", "error": "数据库未就绪,请先执行 migrate 并检查 DB 配置"} if settings.DEBUG: payload["details"] = str(e) return Response(payload) except Exception as e: payload = {"code": "1", "error": "登录服务异常"} if settings.DEBUG: payload["details"] = str(e) return Response(payload) def decrypt_password(self, encrypted_text, private_key): if not private_key or len(private_key) != 16: raise ValueError("invalid sm4 key") cipher = sm4.CryptSM4() cipher.set_key(private_key.encode(), True) encrypted_bytes = base64.b64decode(encrypted_text) decrypted_bytes = cipher.crypt_ecb(encrypted_bytes) return decrypted_bytes.decode()