如何将 django rest api 中的用户与 Auth0 同步

Posted

技术标签:

【中文标题】如何将 django rest api 中的用户与 Auth0 同步【英文标题】:How to synchronize users in django rest api with Auth0 【发布时间】:2017-05-07 18:17:51 【问题描述】:

我使用 Angular 2 作为前端,django rest 框架作为后端。

在前端,我使用 Auth0 来验证用户(https://auth0.com/docs/quickstart/spa/angular2)。在我将 idtoken 发送到我的后端以创建新闻用户之后(https://auth0.com/docs/quickstart/backend/pythonconnected auth0 angular 2中的代码:

import  Component  from '@angular/core';
import  Auth       from './auth.service';
import  AuthHttp   from 'angular2-jwt';
import  Http       from '@angular/http';
import 'rxjs/add/operator/map';

@Component(
  selector: 'ping',
  templateUrl: 'app/ping.template.html'
)

export class PingComponent 
  API_URL: string = 'http://localhost:8000/callback/';
  message: string;

  constructor(private auth: Auth, private http: Http, private authHttp: AuthHttp) 

// the code for sending idtoken to my backend
//correct me please if    I am wrong
  public securedPing() 

    this.message = '';
    this.authHttp.post(`$this.API_URL`,localStorage.getItem('id_token'))
      .map(res => res.json())
      .subscribe(
        data => this.message= data.text,
        error => this.message = error._body || error
      );
  
;

这里是我在 Django 中的后端代码:

 from django.http import Http404

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from django.http import JsonResponse
    from places_management.serializers import UserSerializer
    from django.contrib.auth.models import User
    import jwt

    class Callbacks(APIView):
        authentication_classes = []
        permission_classes = []

        def authenticate(error):

            return Response(error,401)

        def post(self, request, format=None):
            """
            Callback for after user logs in. It creates a
            django auth user if one does not exist, username is the
            user_id retured frrom auth0
            """
            #token = request.META['HTTP_AUTHORIZATION'].split('JWT ')[1]
            auth = request.META.get('HTTP_AUTHORIZATION', None)

            if not auth:
                return Response('code': 'authorization_header_missing', 'description': 'Authorization header is expected',status=status.HTTP_401_UNAUTHORIZED)

            parts = auth.split()

            if parts[0].lower() != 'bearer':
                return authenticate('code': 'invalid_header', 'description':     'Authorization header must start with Bearer')
            elif len(parts) == 1:
                return authenticate('code': 'invalid_header', 'description':     'Token not found')
            elif len(parts) > 2:
                return authenticate('code': 'invalid_header', 'description': 'Authorization header must be Bearer + \s + token')

            token = parts[1]
            try:
                payload = jwt.decode(
                    token,
                    'Z-HWF9cDxGTk7aMZe0A2Ygt81vGBPihz1FCRzJfS87B0mCw1ClQzp1HgA7U3WsSg',
                    audience='GwtnxdwhMWsuGz6JxabDkrNvFhAvn5ZJS'
                    )
            except jwt.ExpiredSignature:
                return authenticate('code': 'token_expired', 'description': 'token is expired')
            except jwt.InvalidAudienceError:
                return authenticate('code': 'invalid_audience', 'description': 'incorrect audience, expected: GwtnxdwhMWsuGz6JxabDkrNvFhvn5ZJS')
            except jwt.DecodeError:
                return authenticate('code': 'token_invalid_signature', 'description': 'token signature is invalid')

            #try:
                #payload = settings.JWT_AUTH['JWT_DECODE_HANDLER'](token)
            #except:
                #return Response('text',status=status.HTTP_401_UNAUTHORIZED)

            user = User.objects.filter(username=payload['sub']).first()
            if(user is None):
                password = User.objects.make_random_password()
                user = User.objects.create_user(
                    username=payload['sub'], password=password)

            serializer = UserSerializer(user, context='user': user)
            return Response(serializer.data, status=status.HTTP_200_OK)

也许我错了,请帮忙

【问题讨论】:

【参考方案1】:

像往常一样,在软件开发中,解决给定问题的方法不止一种,而最合适的解决方案通常需要深入研究很多小细节。

但是,根据您分享的信息,有几件事可以说是安全的。如果您使用 Auth0 进行身份验证,则不应在后端使用密码创建用户。密码用于身份验证,而您将这部分委托给了您,这是一件好事,因为它对您的工作量较少。

话虽如此,仍然有某种与您的应用程序相关联的每用户存储是完全正常的,例如,用于存储用户特定的应用程序设置或其他用户拥有的数据。

为此,您必须将该数据与用户标识符关联起来,该用户标识符可以安全地用于跨多个身份验证会话识别同一用户。该标识符应该是 ID 令牌中包含的 sub 声明值,因为根据规范,该值是稳定的,并且允许您在他们通过 Auth0 完成身份验证时识别重复用户。

总之,您的后端不应创建新的用户身份,因为这属于 Auth0 处理的身份验证范围;相反,您应该将数据与允许您持续识别重复用户的用户标识符相关联。

【讨论】:

我完全同意你的看法,但我如何检索这个 ID 用户?当我从 angular2 发送帖子文件时,我的 Python 服务器响应正常,但在前面我收到一条错误消息,即 [object progress event]。服务器不会向我发送我在代码中定义的任何错误。也许我的角度发布方法是错误的。如果有人可以做一个 angularfire2 和 django 示例来从 auth0 检索用户 ID,那就太好了。谢谢【参考方案2】:

请参考,它确实包含带有 JWT、Auth() 的 Rest Api 的完整演示,Api 与 angular(1) js 集成在前端

https://github.com/rmemon/Angular-JS-django-rest-framework-jwt

【讨论】:

请阅读。我的意思是 Angular 2 和 Auth0。你能帮助 Auth0 和 django 后端吗 我只推荐关于 django 用户模型中的 Auth 和 rest API -- 谢谢 Rahil

以上是关于如何将 django rest api 中的用户与 Auth0 同步的主要内容,如果未能解决你的问题,请参考以下文章