Djangoのハイライト:ユーザーモデルと認証(パート1)

公開: 2022-03-10
簡単な要約↬動的サイトを開発する主な理由の1つは、ユーザーを認証してコンテンツを制限することです。 Djangoは、すぐに使用できる強力なユーザーモデルを提供します。この記事では、安全で直感的なユーザー認証フローを提供するための最良の方法について説明します。

Webサイトには、静的と動的の2つのタイプがあります。 Djangoは、動的なWebサイトを開発するためのフレームワークです。 静的Webサイトは情報のみを表示するWebサイトですが、サーバーに登録される相互作用(単純なページ要求以外)はありません。 静的なWebサイトでは、サーバーはHTML、CSS、およびJavaScriptをクライアントに送信します。それだけです。 より多くの機能には、サーバーが情報を保存し、ページを提供するだけでなくユーザーの操作に応答する動的なWebサイトが必要です。 動的サイトを開発する主な理由の1つは、ユーザーを認証してコンテンツを制限することです。

静的なWebサイトの作成、展開、および管理は、動的なサイトよりも桁違いに簡単で、安価で、安全です。 したがって、動的パラダイムの追加機能がプロジェクトに必要な場合にのみ、動的Webサイトを作成する必要があります。 Djangoは、組み込みのコンポーネントを使用して動的サイトを作成するプロセスを簡素化および合理化します。 動的Webアプリケーションの主要コンポーネントの1つとして、ホイールのような「ユーザーアカウント」オブジェクトは再発明を試みますが、ほとんどの用途には標準の形状が適しています。 Djangoは、すぐに使用できる強力なユーザーモデルを提供します。この記事では、安全で直感的なユーザー認証フローを提供するための最良の方法について説明します。

シリーズのその他のパーツ

  • Djangoのハイライト:テンプレートによる保存行(パート2)
  • Djangoのハイライト:モデル、管理、およびリレーショナルデータベースの活用(パート3)
  • Djangoのハイライト:静的アセットとメディアファイルのラングリング(パート4)

セットアップ

この記事の概念を試すために独自のDjangoアプリケーションを作成する場合は、ディレクトリ(およびできれば仮想環境)を作成してから、次のコマンドを実行できます。

 pip install django django-admin startproject PROJECTNAME cd PROJECTNAME python manage.py startapp APPNAME python manage.py migrate python manage.py runserver

最初のDjangoプロジェクトを作成するためのウォークスルーを探している場合は、Django自身のWebサイトが優れたものを提供します。 この記事では、サンプルプロジェクトを使用していませんが、説明した概念は、ほぼすべてのDjangoアプリケーションに適用されます。

ジャンプした後もっと! 以下を読み続けてください↓

標準ユーザーモデル

基本的に、ユーザーアカウントの概念は、アクセス制御とパーソナライズされたアプリケーションの状態という2つの理由で存在します。 アクセス制御とは、システム上のリソースを利用できるのは一部のユーザーだけであるという考え方です。 パーソナライズされた状態は、アプリケーションの目的に大きく依存しますが、設定、データ、または個々のユーザーに固有のその他のレコードが含まれる場合があります。 DjangoストックUserモデルは、両方のユースケースに賢明なアプローチを提供します。

当初、Djangoアプリケーションには、スーパーユーザーアカウントと通常のユーザーの2種類のユーザーがいます。 スーパーユーザーは、通常のアカウントのすべての属性と特権を持っていますが、Django管理パネルにもアクセスできます。これは、今後の記事で詳しく説明する強力なアプリケーションです。 基本的に、スーパーユーザーは、他のユーザーアカウントを含め、アプリケーション内の任意のデータを作成、編集、または削除できます。

基本的に、ユーザーアカウントの概念は、アクセス制御とパーソナライズされたアプリケーションの状態という2つの理由で存在します。

「「

独自のDjangoアプリケーションでスーパーユーザーを作成するには、次のコマンドを実行します。

 python manage.py createsuperuser

ユーザーアカウントのもう1つの利点は、パーソナライズされたデータをデータベースに保存することです。 デフォルトでは、Djangoはユーザー名とパスワードのみを必要としますが、ユーザーが自分の名前、名前、および電子メールアドレスを入力するためのオプションのフィールドを提供します。 完全なモデルリファレンスは、DjangoのWebサイトで読むことができます。 このモデルの拡張については、以下で説明します。

セキュリティと信頼性

Djangoには、ユーザーモデルに実質的なパスワード管理ミドルウェアが含まれています。 ユーザーパスワードは、完全に数字ではなく、少なくとも8文字である必要があります。また、ユーザー名とあまり一致しない必要があります。また、最も一般的な20,000個のパスワードのリストに含まれていない必要があります。 Djangoストックフォームはこれらの要件を検証します。 パスワードがサーバーに送信されると、保存される前に暗号化されます。デフォルトでは、SHA256ハッシュを使用したPBKDF2アルゴリズムが使用されます。 全体として、デフォルトのパスワードシステムは、開発者の努力なしに堅牢なセキュリティを提供します。 アプリケーションでのパスワードの処理方法を変更する特定の専門知識とやむを得ない理由がない限り、この動作を変更しないでください。

もう1つの便利な組み込み機能は、ユーザー名が一意であるという要件です。 考えてみると、ユーザー名「djangofan1」のユーザーが2人いて、サーバーがそのユーザー名のログイン要求を受信した場合、どちらのユーザーがアプリケーションにアクセスしようとしているかはわかりません。 彼らにとって残念なことに、「djangofan1」に登録しようとする2番目のユーザーは、別の名前、おそらく「djangofan2」を選択する必要があります。 この一意性の制約はデータベースレベルで適用されますが、Djangoが提供するフォームによって再度検証されます。

最後に、ユーザーの削除に関する注意。 ユーザーを削除することも可能ですが、ほとんどの複雑なアプリケーションには、各ユーザーアカウントに関連付けられた多数のリソースがあります。 アタッチされたオブジェクトを削除せずにユーザーを効果的に削除する場合は、代わりにユーザーのis_activeフィールドをfalseに設定します。 その後、これらの他のリソースは、それ自体が削除されるのではなく、アカウントに関連付けられたままになり、ユーザーアカウントは、スーパーユーザーがいつでも再アクティブ化できます。 これによってユーザー名が解放されるわけではありませんが、ユーザー名をランダムで一意の値に変更することと併せてアカウントを非アクティブとして設定すると、同じ効果が得られる可能性があることに注意してください。 最後に、サイトポリシーまたは適用される地域の法律で、ユーザーアカウントを完全に削除可能にする必要がある場合、 is_activeアプローチでは不十分です。

アプリケーションでのパスワードの処理方法を変更する特定の専門知識とやむを得ない理由がない限り、この動作を変更しないでください。

「「

標準的な使用

新しいユーザーアカウントを登録する場合、そのためのビューは、 views.pyで次のようになります。

 from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import UserCreationForm def signup(request): if request.user.is_authenticated: return redirect('/') if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('/') else: return render(request, 'signup.html', {'form': form}) else: form = UserCreationForm() return render(request, 'signup.html', {'form': form})

それを分解しましょう:

  • ユーザーがすでにサインインしている場合は、サインアップページからリダイレクトします。
  • リクエストメソッドがPOSTの場合、ユーザーを作成するためのフォームがすでに入力されていることを意味し、ユーザーを作成するときが来ました。
    • まず、ユーザーが提供したデータを使用して、バックエンドでフォームオブジェクトを作成します。
    • フォームが有効な場合は、ユーザーを作成してログインし、メインページに送信します。
    • それ以外の場合は、無効なデータに関する情報を使用してユーザー作成ページにダンプし直します(たとえば、すでに使用されているユーザー名を要求しました)。
  • それ以外の場合、ユーザーは初めてページにアクセスするため、新しいアカウントを作成するためのフォームが表示されます。

アカウントのサインインを調べています。

 from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import AuthenticationForm def signin(request): if request.user.is_authenticated: return render(request, 'homepage.html') if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('/') else: form = AuthenticationForm(request.POST) return render(request, 'signin.html', {'form': form}) else: form = AuthenticationForm() return render(request, 'signin.html', {'form': form})

別の内訳:

  • ユーザーがすでにサインインしている場合は、サインインページからリダイレクトします。
  • リクエスト方法がPOSTの場合は、サインインのフォームに入力されていることを意味し、アカウントに対してユーザーを認証するときが来ました。
    • まず、ユーザーが提供したデータを使用してユーザーを認証します
    • ユーザー名とパスワードがアカウントに対応している場合は、ユーザーをログインさせます
    • それ以外の場合は、フォーム情報を事前に入力して、サインインページに戻します。
  • それ以外の場合、ユーザーは初めてページにアクセスするため、ログイン用のフォームが表示されます。

最後に、ユーザーは最終的にサインアウトしたいと思うかもしれません。 このリクエストの基本的なコードは単純です。

 from django.shortcuts import render, redirect from django.contrib.auth import logout def signout(request): logout(request) return redirect('/')

ユーザーが自分のアカウントにログインすると、そのデバイスからログアウトするまで、「セッション」が発生します。 この間、ブラウザからの後続のリクエストはアカウントのみのページにアクセスできます。 ユーザーは、同時に複数のセッションをアクティブにすることができます。 デフォルトでは、セッションはタイムアウトしません。

ユーザーがデバイス上でアクティブなセッションを持っている間、ユーザーはrequest.user.is_authenticatedチェックに対してTrueとして登録されます。 ログインしたユーザーのみにページを制限する別の方法は、関数の上にある@login_requiredデコレータです。 同じことを達成する方法は他にも複数ありますが、ここで詳しく説明します。

このレベルの構成が実行したいレベルを超えている場合は、ユーザー管理にさらにすぐに使用できるアプローチがあります。 これらの株式認証ビューは、ユーザー管理用の標準ルート、ビュー、およびフォームを提供し、それらをカスタムURLに割り当てたり、カスタムテンプレートを渡したり、ビューをサブクラス化してさらに制御したりすることで変更できます。

ユーザーモデルの拡張

通常、ユーザーモデルを拡張して、よりきめ細かいアクセス制御を提供するか、アカウントごとにより多くのユーザーデータを保存する必要があります。 以下では、いくつかの一般的なケースについて説明します。

ユーザーモデルからのフィールドの削除

このセクションのヘッダーとは異なり、ユーザーモデルまたは関連するデータベーススキーマに直接変更を加えることは実際にはお勧めしません。 汎用ユーザーモデルは、新しいDjangoプロジェクトのセットアップ中にデフォルトでデータベースに確立されます。 デフォルトのユーザーモデルには多くのことが関係しているため、変更するとアプリケーションに予期しない影響が生じる可能性があります(特に、サードパーティライブラリを使用している場合)。したがって、フィールドの追加または削除は推奨されず、フレームワークによって簡単になりません。

デフォルトでは、ユーザーに必要なフィールドはユーザー名とパスワードの2つだけです。 他のフィールドを使用したくない場合は、それらの存在を無視してください。ユーザーは、名、姓、または電子メールアドレスなしで作成できるためです。 last_loginやdate_joinedなどのデフォルトフィールドのコレクションがあり、不要な場合は無視することもできます。 ユーザーモデルからオプションのフィールドを削除する必要がある実際の技術的な制約がある場合は、それについてすでに知っているので、この記事は必要ありません。

ユーザーモデルのフィールドを削除する一般的な理由は、一意の識別子として電子メールを優先してユーザー名を削除することです。 その場合、フォームデータからユーザーを作成するとき、またはリクエストを認証するときは、電子メールフィールドでの使用に加えて、ユーザー名として電子メールアドレスを入力するだけです。 ユーザー名が電子メールアドレスとしてフォーマットされている場合でも、ユーザー名フィールドは一意性の制約を適用します。 文字列は文字列であり、同じように扱われます。

デフォルトのユーザーモデルには多くのことが関係しているため、特にサードパーティのライブラリを使用している場合は、それを変更するとアプリケーションに予期しない影響が生じる可能性があります。

「「

プロファイルを使用したフィールドの追加

同様に、ユーザーに関する追加情報を保存する場合は、デフォルトのユーザーモデルを変更しないでください。 単一のフィールドの場合でも、既存のユーザーと1対1の関係で独自のオブジェクトを定義します。 この追加モデルは、 Profileと呼ばれることがよくあります。 ユーザーごとにミドルネームと生年月日(dob)を保存したいとします。 Profileは、 models.pyで次のように定義されます。

 from django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) middle_name = models.CharField(max_length=30, blank=True) dob = models.DateField(null=True, blank=True)

カスタムアクセス制御

アプリケーションでは、情報や機能にアクセスするために、さまざまなタイプのユーザーを区別する必要がある場合があります。 Djangoは、カスタムのきめ細かいアクセス制御(権限とグループ)を作成するためのシステムを提供します。

権限は、リソースへのアクセスを決定するオブジェクトです。 ユーザーは1つ以上の権限を持つことができます。 たとえば、製品のテーブルへの読み取りアクセス権と顧客のテーブルへの書き込みアクセス権を持っている場合があります。 パーミッションの正確な実装はアプリケーションによって大幅に異なりますが、Djangoのアプローチにより、データのパーミッションを定義し、それらのパーミッションをユーザーに割り当てることが直感的になります。

企業やその他の大規模な組織向けのアプリケーションは、多くの場合、役割ベースのアクセス制御を実装します。 基本的に、ユーザーはさまざまな役割を持つことができ、それぞれに特定の権限があります。 このパターンを実装するためのDjangoのツールはグループです。 グループには任意の数の権限を設定でき、それぞれを任意の数のグループに割り当てることができます。 その後、ユーザーは直接ではなく、グループへのメンバーシップによってアクセス許可を取得し、アプリケーションの管理を容易にします。

概要:決済プロバイダーの統合

支払いプロセッサを統合する正確なプロセスは、アプリケーションとプロバイダーによって大幅に異なります。 ただし、このプロセスについては一般的な用語で説明します。

支払いのアウトソーシングの主な利点の1つは、プロバイダーがクレジットカード情報などの高度に規制されたデータの保存と検証を担当することです。 次に、サービスは、支払い履歴に関するデータとともに、いくつかの一意のユーザートークンをアプリケーションと共有します。 プロファイルを追加するのと同様に、コアUserに関連付けられたモデルを作成し、そのモデルにデータを保存できます。 パスワードと同様に、機密情報を不適切に保存しないように、プロバイダーとの所定の統合に従うことが重要です。

概要:ソーシャルサインイン

簡単に触れたいもう1つの広範で複雑な分野は、ソーシャルサインインです。 FacebookやGoogleのような大規模なプラットフォーム、およびGitHubのような小規模なサイトは、サービスを使用してユーザーを認証するためのAPIを提供します。 支払いプロバイダーと同様に、これによりデータベースにレコードが作成され、アカウントがデータベース内のアカウントにリンクされます。

ユーザーが新しいログイン資格情報のセットを作成せずに簡単にサインアップできるように、サイトにソーシャル認証を含めることをお勧めします。 アプリケーションが、ソーシャル認証オプションを提供する特定のサイトをすでに使用している顧客のみを対象としている場合は、参入障壁を低くすることで、その市場からユーザーを引き付けるのに役立つ可能性があります。 さらに、アプリケーションがサードパーティのサービスからユーザーのデータにアクセスする場合は、認証中にアカウントをリンクすると、アクセス許可を付与するプロセスが簡素化されます。

ただし、ソーシャル認証を使用することには欠点があります。 サードパーティプロバイダーによるAPIの変更または停止により、アプリケーションの稼働時間または開発アクティビティが中断される可能性があります。 一般に、外部の依存関係はアプリケーションを複雑にします。 最後に、統合するサードパーティのデータ収集および使用ポリシーを検討し、それらがユーザーおよびユーザーの期待に沿っていることを確認することは価値があります。

ソーシャル認証がアプリケーションに適していると判断した場合、幸いなことに、そのためのライブラリがあります。 Python Social Auth for Djangoは、DjangoプロジェクトでPythonのソーシャル認証エコシステムの機能を有効にするためのパッケージです。

まとめ

ユーザーアカウントは普遍的ですが、広く使用されていると、同じ問題を不必要に解決する可能性があります。 この記事で、Djangoで利用できるさまざまな強力な機能を紹介し、ユーザーアカウントを作成する際のアプリケーションの基本的な責任について理解していただければ幸いです。

Django Highlightsは、DjangoでのWeb開発の重要な概念を紹介するシリーズです。 各記事は、フロントエンドの開発者と設計者がコードベースの「残りの半分」をより深く理解できるようにすることを目的とした、Django開発の側面へのスタンドアロンガイドとして書かれています。 これらの記事は主に、理論と慣習を理解するのに役立つように作成されていますが、Django3.0で記述されたコードサンプルがいくつか含まれています。 テンプレート、管理者ユーザー、モデル、フォームなど、この記事で触れたいくつかの概念については、このシリーズの今後の記事で個別に詳しく説明します。

シリーズのその他のパーツ

  • Djangoのハイライト:テンプレートによる保存行(パート2)
  • Djangoのハイライト:モデル、管理、およびリレーショナルデータベースの活用(パート3)
  • Djangoのハイライト:静的アセットとメディアファイルのラングリング(パート4)