""" App 端专用 JWT 认证 Bug #42 fix: the original authenticate() returned None for an empty-string token, which caused the request to be treated as anonymous (unauthenticated) and allowed it to reach protected views without a valid identity. Empty tokens must be rejected with AuthenticationFailed instead. """ from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework_simplejwt.exceptions import AuthenticationFailed class AppJWTAuthentication(JWTAuthentication): """ App 端专用 JWT 认证。 验证 token 中的 user_type 必须为 'app'。 """ def authenticate(self, request): header = self.get_header(request) if header is None: return None raw_token = self.get_raw_token(header) if raw_token is None: return None # Bug #42 fix: explicitly reject empty-string tokens. # The original code had: # # if not token: # return None # BUG – empty string is falsy; this skips auth # # An empty token must raise AuthenticationFailed, not return None, # so the request is blocked rather than treated as anonymous. if not raw_token or raw_token.strip() == b'': raise AuthenticationFailed('Token 不能为空') validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), validated_token def get_user(self, validated_token): from apps.users.models import User # Validate user_type claim (compatible with legacy tokens that omit it) user_type = validated_token.get('user_type', 'app') if user_type not in ('app', None): raise AuthenticationFailed('无效的用户 Token') try: user_id = validated_token.get('user_id') user = User.objects.get(id=user_id) except User.DoesNotExist: raise AuthenticationFailed('用户不存在') if not user.is_active: raise AuthenticationFailed('用户账户已被禁用') return user