DRF集成python-social-auth时如何用simplejwt返回JWT
现有实现
当前基于python-social-auth编写的OAuth令牌交换接口代码如下:
@api_view(http_method_names=['POST']) @permission_classes([AllowAny]) @psa() def oauth_exchange_token_view(request, backend): serializer = SocialAccessTokenSerializer(data=request.data) if serializer.is_valid(raise_exception=True): # set up non-field errors key try: nfe = "non_field_errors" except AttributeError: nfe = 'non_field_errors' try: # 配合@psa装饰器,自动对接配置好的python-social-auth后端完成用户校验与拉取 user = request.backend.do_auth(serializer.validated_data['access_token']) except HTTPError as e: # 向社交认证服务商发起请求出错,一般是传入的access_token格式错误或无效 return Response( {'errors': { 'token': 'Invalid token', 'detail': str(e), }}, status=status.HTTP_400_BAD_REQUEST, ) if user: if user.is_active: # 原逻辑:生成静态永久Token token, _ = Token.objects.get_or_create(user=user) return Response({'access': token.key}) else: return Response( {'errors': {nfe: 'This user account is inactive'}}, status=status.HTTP_400_BAD_REQUEST, ) else: return Response( {'errors': {nfe: "Authentication Failed"}}, status=status.HTTP_400_BAD_REQUEST, )
原有逻辑在用户校验通过后,使用DRF内置的Token模型生成永久静态令牌返回:
token, _ = Token.objects.get_or_create(user=user) return Response({'access': token.key})
需要将这部分逻辑替换为djangorestframework-simplejwt实现的JWT令牌生成逻辑。
改造方法
前置准备
- 已安装
djangorestframework-simplejwt依赖,且完成基础配置(在REST_FRAMEWORK配置项中指定JWT为默认认证类,按需配置令牌过期时间等参数) - 移除原有代码中对
rest_framework.authtoken.models.Token的导入,新增JWT令牌类导入:
from rest_framework_simplejwt.tokens import RefreshToken
替换令牌生成逻辑
将原有生成静态Token的代码块,替换为JWT生成逻辑。djangorestframework-simplejwt提供了RefreshToken.for_user()方法,可以直接为已存在的用户对象签发配对的access访问令牌和refresh刷新令牌:
if user.is_active: # 为用户生成JWT令牌对 refresh = RefreshToken.for_user(user) return Response({ 'access': str(refresh.access_token), 'refresh': str(refresh) })
如果业务不需要返回刷新令牌,也可以仅返回access字段,但常规JWT鉴权场景建议同时返回两个令牌,配合刷新接口实现无感续期。
改造后完整视图代码
@api_view(http_method_names=['POST']) @permission_classes([AllowAny]) @psa() def oauth_exchange_token_view(request, backend): serializer = SocialAccessTokenSerializer(data=request.data) if serializer.is_valid(raise_exception=True): try: nfe = "non_field_errors" except AttributeError: nfe = 'non_field_errors' try: user = request.backend.do_auth(serializer.validated_data['access_token']) except HTTPError as e: return Response( {'errors': { 'token': 'Invalid token', 'detail': str(e), }}, status=status.HTTP_400_BAD_REQUEST, ) if user: if user.is_active: refresh = RefreshToken.for_user(user) return Response({ 'access': str(refresh.access_token), 'refresh': str(refresh) }) else: return Response( {'errors': {nfe: 'This user account is inactive'}}, status=status.HTTP_400_BAD_REQUEST, ) else: return Response( {'errors': {nfe: "Authentication Failed"}}, status=status.HTTP_400_BAD_REQUEST, )
注意:如果自定义了JWT的令牌载荷、序列化规则,
RefreshToken.for_user()方法会自动适配你在simplejwt配置中定义的规则,不需要额外修改逻辑。
内容的提问来源于stack exchange,提问作者Paul Bénéteau
相关产品推荐
相关产品推荐

