无需重定向的 Django 远程身份验证

Posted

技术标签:

【中文标题】无需重定向的 Django 远程身份验证【英文标题】:Django Remote Authentication without redirecting 【发布时间】:2013-11-22 16:26:33 【问题描述】:

在我的应用程序中,我需要通过我的 REST API 对用户进行身份验证。所以我有一个带有用户/密码字段的表单,提交后,我想直接进入“下一页”。所以显然我需要通过 AJAX 提交我的表单,因为我不想被重定向到 API 页面。但是,如果请求将由 javascript 处理,RemoteUserMiddleware 将如何知道我的用户应该经过身份验证?

【问题讨论】:

你在为你的 REST API 使用 sweetpie 吗? 不,rest api 现在是用 pylons 写的,然后会重写到 nodejs。 所以您有一个网站,其中包含一个带有 REST API 的 Pylons 部分和一个 django Web 应用程序,并且您想在 pylons 部分中执行用户身份验证? 没错。 Pylons 部分也在不同的服务器上。 【参考方案1】:

据我了解,您目前的系统架构如下所示:

       --------------             -------------------       -------------------
       | client web | ----------> |    REST API     | ----> | db / persistent |
       |   browser  | <---------- | pylons / nodejs | <---- |     storage     |
       --------------             -------------------       -------------------
            ^ |                         ^ | 
            | |                         | |
            | |                         | v 
            | |                   -----------------         -------------------
            | ------------------> |    django     | ------> | db / persistent |
            --------------------- |               | <------ |     storage     |
                                  -----------------         -------------------

您的问题与在 REST API webapp 中执行身份验证时如何在 django 应用上登录和注销用户有关。

我不确定RemoteUserMiddleware 是否是您正在寻找的,它旨在允许在同一台服务器上使用 wsgi 运行 django 时通过 Apache 网络服务器层进行身份验证。该名称与 REMOTE_USER unix 系统变量有关,这是 apache 中的一种老式身份验证方法。

让客户端成为 django 和您的 REST API 之间身份验证链中的中介似乎是不明智的,这似乎本质上是不安全的。相反,django 可以直接调用 REST API 对用户进行身份验证,然后创建相应的 django.contrib.auth.models.User 对象来本地存储,这是在自定义身份验证后端执行的,请参阅 here。

类似:

from django.contrib.auth.models import User
import requests

class RestBackend(object):
    supports_inactive_user = False

    def authenticate(self, username=None, password=None):
        rest_response = requests.post('http://your.rest.interface/auth', 
            data= 'username' : username, 'password' : password ).json()

        if rest_response['error'] == 'None':
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                user = User(username=username, password=password)
                user.save()
            return user
        return user

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

这使用requests 库通过同步 http 请求调用 REST API 以登录用户,然后创建用户对象的本地实例(如果尚不存在)。远程认证有更复杂的协议,如果需要,http://oauth.net/2/就是一个例子。

这个后端应该在settings.py文件中指定

AUTHENTICATION_BACKENDS = ('my.classy.django.app.RestBackend')

然后您的 django 应用程序可以在其视图中使用 authenticatelogin 函数,使用 http 或 json,更多信息 here。

Django 会将request.user 设置为AnonymousUser 类的对象,直到用户登录,文档here。这允许您在不使用重定向的情况下区分视图中的这些用户:

  from django.http import HttpResponse
  from django.utils import simplejson
  from myApp.models impor InfoObject

  def infoPage(request):
        # return info objects for logged in user, or all info objects otherwise
        if request.user.is_authenticated():
            infoObjects = InfoObject.objects.filter(user=request.user).orderby("-pubdate")
        else:
            infoObjects = InfoObject.objects.orderby("-pubdate")
        return HttpResponse(simplejson.dumps(infoObjects), content_type = "application/json") 

或者,如果您希望在页面上显示“用户配置文件”框,也可以使用 ***:

 # helper function that can be called from all your views
 def getUserInfo(request):
      if request.user.is_authenticated():
          return UserInfo.objects.get(user=user)
      else:
          return []

 def randomPage(request):
       info = getUserInfo(request)
       .....other page logic....
       return HttpResponse('['+simplejson.dumps(..pageData..)+','+simplejson.dumps(info)+']', content_type = "application/json") 

如果相反,您使用模板而不是 ajax 来呈现您的页面,则可以将此逻辑传递给模板,在用户登录时显示区域,而无需使用重定向:

% extends "base.html" %

% block userInfo %
    <div id="userArea">
    % if user.is_authenticated %
        User:  user.username <br />
        geezer score:  userProfile.geezerScore <br />
        <input type="button" value="log out" />
    % else %
        Username: <input type="text" id="username" />
        password: <input type="password" id="password" />
        <input type="button" value="log in" />
    % endif %
    </div>
% endblock %

这依赖于视图基于模板的用户对象,并且需要 javascript 连接后端的身份验证。

也可以使用render_to_string() 以模板呈现上下文,并将其返回给ajax 请求而不是json。从而允许html在服务器上渲染并返回给客户端,而无需在客户端重新加载页面。

通过这种方式,可以让 django 呈现一些模板并使用一些 ajax 响应来补充对 REST 接口的 ajax 请求。

这和你要找的一样吗?

【讨论】:

以上是关于无需重定向的 Django 远程身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Inertia (Vue) - 无需重定向即可进行身份验证

django,身份验证后重定向到ajax操作

测试 Django 管理操作(重定向/身份验证问题)

Django 身份验证 - 错误的重定向 url 到登录页面

Django用户身份验证:登录后不重定向

我该如何处理 Django 中的 spotify api 身份验证重定向 uri?