温馨提示:本文翻译自stackoverflow.com,查看原文请点击:azure - How should I be implementing user SSO with AAD in a Django application (using the Django Microsoft A
azure azure-active-directory django single-sign-on

azure - 我应该如何在Django应用程序中使用AAD实现用户SSO(使用Django Microsoft A

发布于 2020-04-07 11:18:36

我正在开发安装Django Microsoft Auth的Django(2.2.3)应用程序,以使用Azure AD处理SSO。我已经能够按照快速入门文档使用我的Microsoft身份或添加到Django用户表中的标准用户名和密码登录到Django Admin面板。所有这些都是开箱即用的,很好。

我的问题(确实)只是“接下来我要做什么?”。从用户的角度来看,我希望他们:

  1. 导航到我的应用程序(example.com/或example.com/content)-Django将意识到它们未通过身份验证,或者
    • 自动将它们重定向到同一窗口中的SSO门户,或者
    • 将他们重定向到example.com/login,这要求他们单击一个将在窗口中打开SSO门户的按钮(这是默认管理情况下的情况)
  2. 允许他们登录并通过其Microsoft帐户使用MFA
  3. 成功后,将它们重定向到我的@login_required页面(example.com/content)

当前,在导航的根目录(example.com/)中,我具有以下内容:

    def index(request):
        if request.user.is_authenticated:
            return redirect("/content")
        else:
            return redirect("/login")

我最初的想法只是将其更改redirect("/login")redirect(authorization_url)-这就是我的问题开始的地方。

据我所知,没有任何方法可以获取上下文处理器的当前实例(?)或microsoft_auth插件的后端来调用该authorization_url()函数并从重定向用户views.py

好吧...然后我想我将实例化MicrosoftClient生成身份验证URL 类。这没有用-不能100%地确定为什么,但是它认为这可能与MicrosoftClient后端/上下文处理器上的实际实例使用的某些状态变量与我的实例不一致有关。

最后,我尝试模仿自动/admin页面的功能-呈现一个SSO按钮供用户单击,然后在单独的窗口中打开Azure门户。经过一番研究之后,我意识到我从根本上遇到了同样的问题-身份验证URL作为内联JS传递到管理登录页面模板中,该内联JS随后用于在客户端异步创建Azure窗口。

作为健全性检查,我尝试手动导航到admin登录页面中显示的身份验证URL,并且确实有效(尽管重定向至/content无效)。

在这一点上,考虑到我认为我自己很难做到,我觉得我正在以错误的方式来做这件事。可悲的是,我找不到任何有关如何完成此部分过程的文档。

那么,我在做什么错呢?

查看更多

提问者
J.B
被浏览
124
J.B 2020-02-03 18:30

再过几天,我最终自己解决了这些问题,并了解了有关Django工作原理的更多信息。

我所缺少的链接是来自(第三方)Django模块的上下文处理器如何/在何处将其上下文传递到最终呈现的页面。我没有意识到authorisation_url默认情况下,我也可以在任何模板中访问microsoft_auth包中的变量(例如其模板中使用的变量)。知道了这一点,我能够实现管理面板使用的基于JS的相同登录过程的稍微简化的版本。

假设将来有任何人阅读我正在经历的(学习)相同的过程(特别是使用此软件包),我可能可以猜到接下来的两个问题……

第一个是“我已经成功登录...如何代表用户做任何事情?!”。可以假设您将获得用户的访问令牌以用于将来的请求,但是在编写此程序包时,默认情况下似乎并没有以任何明显的方式进行操作。该软件包的文档仅能使您登录到管理面板。

(在我看来,答案不是那么明显)是您必须设置MICROSOFT_AUTH_AUTHENTICATE_HOOK一个可以在成功进行身份验证时调用的函数。它将传递给登录用户(模型)及其令牌JSON对象,供您随意处理。经过深思熟虑,我选择使用扩展用户模型,AbstractUser并仅将每个用户的令牌与其他数据保持在一起。

models.py

class User(AbstractUser):
    access_token = models.CharField(max_length=2048, blank=True, null=True)
    id_token = models.CharField(max_length=2048, blank=True, null=True)
    token_expires = models.DateTimeField(blank=True, null=True)

aad.py

from datetime import datetime
from django.utils.timezone import make_aware

def store_token(user, token):
    user.access_token = token["access_token"]
    user.id_token = token["id_token"]
    user.token_expires = make_aware(datetime.fromtimestamp(token["expires_at"]))
    user.save()

settings.py

MICROSOFT_AUTH_EXTRA_SCOPES = "User.Read"
MICROSOFT_AUTH_AUTHENTICATE_HOOK = "django_app.aad.store_token"

请注意MICROSOFT_AUTH_EXTRA_SCOPES设置,这可能是您的第二个/ SCOPE_MICROSOFT = ["openid", "email", "profile"]附加问题-软件包中默认的范围设置为,如何添加更多的范围并不明显。User.Read至少需要添加请记住,该设置需要一串用空格分隔的范围,而不是列表。

获得访问令牌后,您就可以向Microsoft Graph API发出请求了。他们的Graph Explorer在帮助解决此问题方面非常有用。