Backend (Django 4.2 + DRF): - Admin auth with SimpleJWT - Volcengine API client with HMAC-SHA256 signing - IAM user management (create/sync/import/disable/enable) - Billing query with pagination - Feishu webhook notifications (async) - APScheduler for periodic spending checks - AES-256 encrypted credential storage - API key auth for external system integration Frontend (Vue 3 + Element Plus): - Login page - Dashboard with stats overview - IAM user list with per-user threshold config - Billing view with spending progress bars - Alert history with type filtering - Settings page for global config and Volcengine account management Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
from django.contrib.auth import authenticate
|
|
from rest_framework import status
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
|
|
from .serializers import LoginSerializer, UserInfoSerializer
|
|
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([AllowAny])
|
|
def login_view(request):
|
|
serializer = LoginSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
user = authenticate(
|
|
username=serializer.validated_data['username'],
|
|
password=serializer.validated_data['password'],
|
|
)
|
|
if not user:
|
|
return Response(
|
|
{'error': 'invalid_credentials', 'message': '用户名或密码错误'},
|
|
status=status.HTTP_401_UNAUTHORIZED,
|
|
)
|
|
if not user.is_active:
|
|
return Response(
|
|
{'error': 'user_disabled', 'message': '账号已停用'},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
|
|
refresh = RefreshToken.for_user(user)
|
|
return Response({
|
|
'access': str(refresh.access_token),
|
|
'refresh': str(refresh),
|
|
'user': UserInfoSerializer(user).data,
|
|
})
|
|
|
|
|
|
@api_view(['POST'])
|
|
def refresh_view(request):
|
|
token = request.data.get('refresh')
|
|
if not token:
|
|
return Response(
|
|
{'error': 'missing_token', 'message': '缺少 refresh token'},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
try:
|
|
refresh = RefreshToken(token)
|
|
return Response({'access': str(refresh.access_token)})
|
|
except Exception:
|
|
return Response(
|
|
{'error': 'invalid_token', 'message': 'token 无效或已过期'},
|
|
status=status.HTTP_401_UNAUTHORIZED,
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
def me_view(request):
|
|
return Response(UserInfoSerializer(request.user).data)
|