| import requests |
| from rest_framework.authentication import BaseAuthentication |
| from rest_framework.exceptions import AuthenticationFailed |
| from django.contrib.auth.models import User |
| from django.conf import settings |
| import logging |
| import os |
| from pathlib import Path |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| class ThirdPartyUserManager: |
| """第三方用户管理工具类""" |
| |
| @classmethod |
| def get_or_create_user_from_third_party(cls, third_party_username): |
| """ |
| 根据第三方用户名获取或创建本地用户 |
| """ |
| from api.models import ThirdPartyUserMapping |
| |
| |
| try: |
| mapping = ThirdPartyUserMapping.objects.get(third_party_username=third_party_username) |
| return mapping.user |
| except ThirdPartyUserMapping.DoesNotExist: |
| pass |
| |
| |
| |
| username = f"tp_{third_party_username}" |
| |
| |
| if User.objects.filter(username=username).exists(): |
| |
| counter = 1 |
| base_username = username |
| while User.objects.filter(username=username).exists(): |
| username = f"{base_username}_{counter}" |
| counter += 1 |
| |
| |
| user = User.objects.create( |
| username=username, |
| email=f"{third_party_username}@thirdparty.com", |
| first_name=third_party_username, |
| ) |
| |
| |
| ThirdPartyUserMapping.objects.create( |
| user=user, |
| third_party_user_id=hash(third_party_username) % 2147483647, |
| third_party_username=third_party_username |
| ) |
| |
| |
| cls.create_user_directories(user) |
| |
| logger.info(f"Created new local user {username} for third party user {third_party_username}") |
| |
| return user |
| |
| @classmethod |
| def get_user_by_third_party_username(cls, third_party_username): |
| """ |
| 根据第三方用户名获取本地用户 |
| """ |
| from api.models import ThirdPartyUserMapping |
| |
| try: |
| mapping = ThirdPartyUserMapping.objects.get(third_party_username=third_party_username) |
| return mapping.user |
| except ThirdPartyUserMapping.DoesNotExist: |
| return None |
| |
| @classmethod |
| def create_user_directories(cls, user): |
| """ |
| 为用户创建必要的数据目录结构 |
| """ |
| try: |
| |
| media_root = Path(settings.MEDIA_ROOT) |
| |
| |
| user_base_dir = media_root / 'users' / str(user.id) |
| projects_dir = user_base_dir / 'projects' |
| |
| |
| user_base_dir.mkdir(parents=True, exist_ok=True) |
| projects_dir.mkdir(parents=True, exist_ok=True) |
| |
| logger.info(f"Created directory structure for user {user.username} at {user_base_dir}") |
| |
| except Exception as e: |
| logger.error(f"Failed to create directories for user {user.username}: {e}") |
| |
| @classmethod |
| def get_user_by_third_party_id(cls, third_party_user_id): |
| """ |
| 根据第三方用户ID获取本地用户 |
| """ |
| from api.models import ThirdPartyUserMapping |
| |
| try: |
| mapping = ThirdPartyUserMapping.objects.get(third_party_user_id=third_party_user_id) |
| return mapping.user |
| except ThirdPartyUserMapping.DoesNotExist: |
| return None |
|
|
| class ThirdPartyAuth: |
| """第三方认证工具类""" |
| |
| BASE_URL = "http://27.223.62.254:10008" |
| |
| @classmethod |
| def login(cls, username, password): |
| """ |
| 登录获取token |
| """ |
| try: |
| url = f"{cls.BASE_URL}/login/{username},{password},1" |
| headers = { |
| 'accept': 'application/json', |
| 'X-CSRFToken': 'ARNjGjIoXRiA5I5LwmKcUDB5GGzPtMofGDJW5UcBsjWAolmvA8iZoLjWMxFepakY' |
| } |
| |
| response = requests.get(url, headers=headers, timeout=10) |
| |
| if response.status_code == 200: |
| data = response.json() |
| if 'token' in data: |
| return { |
| 'success': True, |
| 'token': data['token'], |
| 'user_id': data.get('user_id'), |
| 'username': data.get('username'), |
| 'message': data.get('msg', '') |
| } |
| |
| return { |
| 'success': False, |
| 'message': f'登录失败: HTTP {response.status_code}' |
| } |
| |
| except requests.RequestException as e: |
| logger.error(f"Third party login error: {e}") |
| return { |
| 'success': False, |
| 'message': f'登录服务连接失败: {str(e)}' |
| } |
| |
| @classmethod |
| def validate_token(cls, token): |
| """ |
| 验证token有效性 |
| """ |
| try: |
| url = f"{cls.BASE_URL}/user/valid_token/" |
| headers = { |
| 'accept': 'application/json', |
| 'X-CSRFToken': 'ARNjGjIoXRiA5I5LwmKcUDB5GGzPtMofGDJW5UcBsjWAolmvA8iZoLjWMxFepakY' |
| } |
| |
| files = {'user_token': (None, token)} |
| |
| response = requests.post(url, headers=headers, files=files, timeout=10) |
| |
| if response.status_code == 200: |
| data = response.json() |
| if data.get('code') == '200' and data.get('message') == 'succeed': |
| return { |
| 'valid': True, |
| 'data': data.get('data', {}), |
| 'user_name': data.get('data', {}).get('user_name') |
| } |
| |
| return { |
| 'valid': False, |
| 'message': f'Token验证失败: HTTP {response.status_code}' |
| } |
| |
| except requests.RequestException as e: |
| logger.error(f"Token validation error: {e}") |
| return { |
| 'valid': False, |
| 'message': f'Token验证服务连接失败: {str(e)}' |
| } |
|
|
| @classmethod |
| def get_user_info_by_token(cls, token): |
| """ |
| 通过token获取用户信息 |
| """ |
| validation_result = cls.validate_token(token) |
| if validation_result['valid']: |
| return validation_result['data'] |
| return None |
|
|
|
|
| class ThirdPartyTokenAuthentication(BaseAuthentication): |
| """ |
| 第三方Token认证类 |
| 只接受Authorization header中的token进行认证 |
| """ |
| |
| def authenticate(self, request): |
| """ |
| 验证请求中的token |
| """ |
| |
| token = self.get_token_from_request(request) |
| |
| if not token: |
| return None |
| |
| |
| user = self.get_or_create_user(token) |
| |
| if not user: |
| raise AuthenticationFailed('Invalid token') |
| |
| return (user, token) |
| |
| def get_token_from_request(self, request): |
| """ |
| 从请求中获取token |
| 只支持Authorization header方式: |
| - Authorization: Token <token> |
| - Authorization: Bearer <token> |
| """ |
| |
| auth_header = request.META.get('HTTP_AUTHORIZATION') |
| if not auth_header: |
| return None |
| |
| |
| if auth_header.startswith('Token '): |
| return auth_header[6:] |
| |
| |
| if auth_header.startswith('Bearer '): |
| return auth_header[7:] |
| |
| |
| return None |
| |
| def get_or_create_user(self, token): |
| """ |
| 获取或创建用户 |
| """ |
| from api.models import TokenStorage |
| |
| |
| try: |
| token_storage = TokenStorage.objects.get(token=token) |
| |
| token_storage.save() |
| return token_storage.user |
| except TokenStorage.DoesNotExist: |
| pass |
| |
| |
| validation_result = ThirdPartyAuth.validate_token(token) |
| |
| if not validation_result['valid']: |
| logger.warning(f"Invalid token: {token[:8]}...") |
| return None |
| |
| |
| user_name = validation_result.get('user_name') |
| if not user_name: |
| logger.error(f"No user_name in validation result for token: {token[:8]}...") |
| return None |
| |
| |
| user = ThirdPartyUserManager.get_or_create_user_from_third_party(user_name) |
| |
| |
| try: |
| TokenStorage.objects.update_or_create( |
| token=token, |
| defaults={ |
| 'user': user, |
| 'third_party_user_id': hash(user_name) % 2147483647, |
| 'third_party_username': user_name, |
| } |
| ) |
| logger.info(f"Token stored for user: {user_name}") |
| except Exception as e: |
| logger.error(f"Failed to store token: {e}") |
| |
| return user |