如何将 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 同步的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Django Rest Framework 可浏览 API 接口限制为管理员用户

如何在 Django Rest Framework 中散列 Django 用户密码?

如何保护 Django Rest Framework 中注册和登录的 API?

如何在 Django Rest Framework 的 REST API 中为数组数据编写序列化程序?

如何在 Django REST Framework 中的单元测试期间登录用户?

Django Rest Framework Serializer的简单使用