我应该如何在 Django 应用程序中使用 AAD 实现用户 SSO(使用 Django Microsoft Authentication Backend 模块)? [英] How should I be implementing user SSO with AAD in a Django application (using the Django Microsoft Authentication Backend module)?

查看:16
本文介绍了我应该如何在 Django 应用程序中使用 AAD 实现用户 SSO(使用 Django Microsoft Authentication Backend 模块)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing a Django (2.2.3) application with Django Microsoft Auth installed to handle SSO with Azure AD. I've been able to follow the quickstart documentation to allow me to log into the Django Admin panel by either using my Microsoft identity, or a standard username and password I've added to the Django user table. This all works out of the box and is fine.

我提出的问题(真的)很简单,就是我接下来要做什么?".从用户的角度来看,我希望他们:

My question put (really) simply is "What do I do next?". From a user's perspective, I'd like them to:

  1. 导航到我的应用程序(example.com/或 example.com/content) - Django 将意识到它们没有经过身份验证,并且要么
    • 自动将它们重定向到同一窗口中的 SSO 门户,或
    • 将他们重定向到 example.com/login,这要求他们点击一个按钮以打开 SSO窗口中的门户(这是默认管理案例中发生的情况)

目前,在我的导航 (example.com/) 的根目录下,我有这个:

Currently, at the root of my navigation (example.com/), I have this:

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

我最初的想法是简单地将 redirect("/login") 更改为 redirect(authorization_url) - 这就是我的问题开始的地方..

My original idea was to simply change the redirect("/login") to redirect(authorization_url) - and this is where my problems start..

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

As far as I can tell, there isn't any way to get the current instance(?) of the context processor or backend of the microsoft_auth plugin to call the authorization_url() function and redirect the user from views.py.

好的...然后我想我只是实例化生成身份验证 URL 的 MicrosoftClient 类.这不起作用 - 不是 100% 确定原因,但它认为这可能与后端/上下文处理器上实际 MicrosoftClient 实例使用的某些状态变量与我的实例.

Ok... Then I thought I'd just instantiate the MicrosoftClient class that generates the auth URL. This didn't work - not 100% sure why, but it think it may have something to do with the fact that some state variable used by the actual MicrosoftClient instance on the backend/context processor is inconsistent with my instance.

最后,我尝试模仿自动 /admin 页面的功能 - 显示 SSO 按钮供用户单击,然后在单独的窗口中打开 Azure 门户.经过一番挖掘,我意识到我基本上有同样的问题 - 身份验证 URL 作为内联 JS 传递到管理登录页面模板,稍后用于在客户端异步创建 Azure 窗口.

Finally, I tried to mimic what the automatic /admin page does - present an SSO button for the user to click, and open the Azure portal in a separate window. After digging around a bit, I realise that I fundamentally have the same problem - the auth URL is passed into the admin login page template as inline JS, which is later used to create the Azure window asynchronously on the client side.

作为健全性检查,我尝试手动导航到 auth URL,因为它显示在管理登录页面中,并且确实有效(尽管重定向到 /content 没有).

As a sanity check, I tried to manually navigate to the auth URL as it is presented in the admin login page, and that did work (though the redirect to /content didn't).

在这一点上,考虑到我认为自己正在为自己做这件事有多困难,我觉得我正在以完全错误的方式处理这整件事.遗憾的是,我找不到任何关于如何完成这部分过程的文档.

At this point, given how difficult I think I'm making it for myself, I'm feel like I'm going about this whole thing completely the wrong way. Sadly, I can't find any documentation on how to complete this part of the process.

那么,我做错了什么?!

So, what am I doing wrong?!

推荐答案

又过了几天,我最终自己解决了问题,也了解了更多关于 Django 的工作原理.

A couple more days at this and I eventually worked out the issues myself, and learned a little more about how Django works too.

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

The link I was missing was how/where context processors from (third party) Django modules pass their context's through to the page that's eventually rendered. I didn't realise that variables from the microsoft_auth package (such as the authorisation_url used in its template) were accessible to me in any of my templates by default as well. Knowing this, I was able to implement a slightly simpler version of the same JS based login process that the admin panel uses.

假设将来阅读本文的任何人都在经历与我相同的(学习)过程(尤其是使用此软件包),我也许可以猜到您接下来会遇到的几个问题...

Assuming that anyone reading this in the future is going through the same (learning) process I have (with this package in particular), I might be able to guess at the next couple of questions you'll have...

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

The first one was "I've logged in successfully...how do I do anything on behalf of the user?!". One would assume you'd be given the user's access token to use for future requests, but at the time of writing this package didn't seem to do it in any obvious way by default. The docs for the package only get you as far as logging into the admin panel.

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

The (in my opinion, not so obvious) answer is that you have to set MICROSOFT_AUTH_AUTHENTICATE_HOOK to a function that can be called on a successful authentication. It will be passed the logged in user (model) and their token JSON object for you to do with as you wish. After some deliberation, I opted to extend my user model using AbstractUser and just keep each user's token with their other data.

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

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 .请记住,该设置需要一串空格分隔的范围,而不是列表.

Note the MICROSOFT_AUTH_EXTRA_SCOPES setting, which might be your second/side question - The default scopes set in the package as SCOPE_MICROSOFT = ["openid", "email", "profile"], and how to add more isn't made obvious. I needed to add User.Read at the very least. Keep in mind that the setting expects a string of space separated scopes, not a list.

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

Once you have the access token, you're free to make requests to the Microsoft Graph API. Their Graph Explorer is extremely useful in helping out with this.

这篇关于我应该如何在 Django 应用程序中使用 AAD 实现用户 SSO(使用 Django Microsoft Authentication Backend 模块)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆