Как мне реализовать SSO пользователя с AAD в приложении Django (с использованием модуля Django Microsoft Authentication Backend)? - PullRequest
2 голосов
/ 31 января 2020

Я разрабатываю приложение Django (2.2.3) с Django Microsoft Auth , установленным для обработки единого входа с Azure AD. Я смог воспользоваться документацией по быстрому запуску, чтобы я мог войти в панель администратора Django, используя свое удостоверение Microsoft или стандартные имя пользователя и пароль, которые я добавил в таблицу пользователей Django. Это все работает из коробки и хорошо.

Мой вопрос, поставленный (действительно) просто: «Что мне делать дальше?». С точки зрения пользователя, я бы хотел, чтобы они:

  1. Перейдите к моему приложению (example.com/ или example.com/content) - Django поймет, что они не аутентифицированы, и либо
    • автоматически перенаправляет их на портал SSO в том же окне, либо
    • перенаправляет их на example.com/login, что требует от них нажатия кнопки, которая откроет портал SSO в окно (что происходит в случае администратора по умолчанию)
  2. Разрешить им входить в систему и использовать MFA со своей учетной записью Microsoft
  3. После успешного перенаправления их на мой @login_required pages (example.com/content)

В настоящее время, в root моей навигации (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() d перенаправить пользователя из views.py.

Хорошо ... Тогда я подумал, что просто создам экземпляр класса MicrosoftClient, который генерирует URL-адрес аутентификации. Это не сработало - не уверен на 100%, почему, но он думает, что это может иметь какое-то отношение к тому факту, что некоторая переменная состояния, используемая фактическим экземпляром MicrosoftClient на процессоре бэкэнда / контекста, не соответствует моему экземпляру. *

Наконец, я попытался имитировать c, что делает страница автоматизации c /admin - предоставить пользователю кнопку SSO, чтобы открыть ее, и открыть портал Azure в отдельном окне. Немного покопавшись, я понимаю, что в принципе у меня та же проблема - URL-адрес авторизации передается в шаблон страницы входа администратора как встроенный JS, который позже используется для асинхронного создания окна Azure на стороне клиента.

В качестве проверки работоспособности я попытался вручную перейти к URL-адресу аутентификации, как он представлен на странице входа администратора, и это сработало (хотя перенаправление на /content не сработало).

В этот момент, учитывая, насколько сложно мне кажется, что я делаю это для себя, я чувствую, что делаю все это совершенно неправильно. К сожалению, я не могу найти никакой документации о том, как завершить эту часть процесса.

Итак, что я делаю не так?!

1 Ответ

1 голос
/ 03 февраля 2020

Еще пару дней на этом, и я, в конце концов, сам решил проблемы и узнал немного больше о том, как работает Django.

Ссылка, которую я пропустил, была о том, как / откуда возникли контекстные процессоры ( сторонние) Django модули передают свой контекст на страницу, которая в конечном итоге отображается. Я не осознавал, что переменные из пакета microsoft_auth (например, authorisation_url, использованные в его шаблоне) были доступны для меня в любом из моих шаблонов по умолчанию. Зная это, я смог реализовать немного более простую версию того же самого процесса входа в систему на основе JS, который использует панель администратора.

Предполагая, что любой, кто читает это в будущем, проходит тот же (обучающий) процесс У меня есть (с этим пакетом, в частности), я мог бы догадаться на следующих двух вопросов, которые у вас будут ...

Первый из них был "Я успешно вошел в систему ... как я делаю что-нибудь от имени пользователя ?! " Можно было бы предположить, что вам будет выдан токен доступа пользователя для использования в будущих запросах, но на момент написания этого пакета, по-видимому, по умолчанию он не выполнялся каким-либо очевидным образом. Документы для пакета помогут вам войти в панель администратора.

(На мой взгляд, не очень очевидный ответ), вы должны установить MICROSOFT_AUTH_AUTHENTICATE_HOOK для функции, которая может быть вызвана на успешной аутентификации. Он будет передан вошедшему в систему пользователю (модели) и его маркерному JSON объекту, который вы можете использовать при работе с sh. После некоторых размышлений я решил расширить свою модель пользователя с помощью 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 чрезвычайно полезен для помощи в этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...