web-dev-qa-db-ja.com

DjangoアプリケーションでDjango Microsoft認証バックエンドモジュールを使用して)にAADでユーザーSSOを実装するにはどうすればよいですか?

Django(2.2.3)アプリケーションを開発しています Django Microsoft Auth をインストールして、Azure ADでSSOを処理します。クイックスタートドキュメントをたどることができましたDjango管理パネルにMicrosoft IDを使用するか、Django user tableに追加した標準のユーザー名とパスワードを使用して。これはすべてそのまま使用でき、問題ありません。

私の質問は(本当に)単純に「次に何をするか?」です。ユーザーの観点から、私は彼らにしてもらいたい:

  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_から。

それでは、認証URLを生成するMicrosoftClientクラスをインスタンス化するだけだと思いました。これは機能しませんでした-理由は100%わかりませんが、バックエンド/コンテキストプロセッサの実際のMicrosoftClientインスタンスで使用されるいくつかの状態変数が私のインスタンスと矛盾しているという事実に関係している可能性があります。

最後に、自動の_/admin_ページの動作を模倣しようとしました。ユーザーがクリックするSSOボタンを表示し、別のウィンドウでAzureポータルを開きます。少し調べたところ、基本的に同じ問題があることに気づきました。認証URLは、インラインのJSとして管理者ログインページテンプレートに渡されます。これは、後でクライアント側で非同期にAzureウィンドウを作成するために使用されます。

健全性チェックとして、管理者ログインページに表示されている認証URLに手動で移動しようとしましたが、機能しました(ただし、_/content_へのリダイレクトは機能しませんでした)。

この時点で、自分で作るのは難しいと思うので、私はこの全体を完全に間違った方法で進んでいるように感じています。残念ながら、プロセスのこの部分を完了する方法に関するドキュメントは見つかりません。

だから、私は何が間違っているのですか?

4
J.B

これで数日後、私は最終的に自分で問題を解決し、Djangoがどのように機能するかについてもう少し学びました。

私が欠けていたリンクは、(サードパーティ)からのコンテキストプロセッサがどのように/どこにあるかでしたDjango=モジュールは、最終的にレンダリングされるページにコンテキストを渡します。Microsoft_authパッケージ(テンプレートで使用されているauthorisation_urlなど)は、デフォルトでどのテンプレートでもアクセスできます。これを知って、管理パネルと同じJSベースのログインプロセスのややシンプルなバージョンを実装できました使用します。

将来これを読む人が私と同じ(特にこのパッケージで)同じ(学習)プロセスを経験していると仮定すると、次のいくつかの質問で推測できるかもしれません...

1つ目は、「正常にログインしました...ユーザーに代わって何をすればよいですか?」でした。将来のリクエストに使用するユーザーのアクセストークンが与えられると想定する人もいますが、このパッケージを作成した時点では、このパッケージはデフォルトでは明らかな方法でそれを行っていないようです。パッケージのドキュメントでは、管理パネルにログインするまでしかアクセスできません。

(私の意見では、それほど明白な答えではありません)は、認証が成功したときに呼び出すことができる関数に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の設定に注意してください。これは2番目の質問である可能性があります-パッケージでSCOPE_Microsoft = ["openid", "email", "profile"]として設定されているデフォルトのスコープと、さらに追加する方法は明らかにされていません。少なくともUser.Readを追加する必要がありました。この設定では、リストではなく、スペースで区切られたスコープの文字列を想定していることに注意してください。

アクセストークンを取得したら、Microsoft Graph APIに自由にリクエストを送信できます。彼らの Graph Explorer は、これを手助けするのに非常に役立ちます。

3
J.B