ログイン認証バックエンドの実装
Djangoのデフォルトの認証システムは、認証モジュールを提供してきました。認証システムは含まれています:
- ユーザー管理
- [アクセス許可[RBAC]
- ユーザグループの[役割グループ]
- パスワードのハッシュ化システム
- ユーザーがログオンしたり、フォームやビューのコンテンツを表示します
- プラグ可能なバックエンドシステム
Djangoのデフォルトのユーザ認証メカニズムは、セッションメカニズムを依存している、我々は達成するために私たちを助けるために、Djangoの認証システムをドッキング、その後、プロジェクト内のトークン文字列に格納されているユーザーの資格情報の身元をJWT認証機構を導入し、そして:
- ユーザーデータモデル
- ユーザーパスワードの暗号化と認証
- ユーザー権限システム
DjangoのUserモデルクラス
Djangoの認証システムは、ユーザのデータを保存するために、ユーザーモデルクラスのユーザーを提供し、デフォルトのユーザーは、以下の共通の基本的なフィールドが含まれています。
フィールド名 | フィールド説明 |
---|---|
username |
必須。150文字以下。ユーザー名には含まれていてもよい_ 、英数字、@ 、、+ . および- 文字が。 |
first_name |
オプションblank=True ()。30個の文字に等しい未満。 |
last_name |
オプションblank=True ()。30個の文字に等しい未満。 |
email |
オプションblank=True ()。E-mailアドレス。 |
password |
必須。ハッシュされたパスワード文字列。(Djangoは元のパスワードを保存しません)。元のパスワードは、無限に長いことができ、任意の文字を含めることができます。 |
groups |
そして、Group の間には多くの関係。 |
user_permissions |
そして、Permission の間には多くの関係。 |
is_staff |
ブール値。管理者ユーザーがサイトにアクセスすることができます設定されています。 |
is_active |
ブール値。ユーザーアカウントがアクティブであることを示します。ユーザーがログインできるかどうかを制御するために使用されるが、アカウントの状態を使用することが記載されていません。 |
is_superuser |
それは、スーパーユーザーであるかどうか。スーパーユーザはすべての権限を持っています。 |
last_login |
ユーザーが最後にログインした時間。 |
date_joined |
タイムアカウントが作成されました。アカウントを作成すると、デフォルトの設定では、現在の日付/時刻です。 |
一般的な方法:
-
set_password
(raw_password)与えられた生の文字列にユーザーのパスワードを設定して、パスワードを担当しています。それは保存されません
User
オブジェクトを。以下のようNone
でraw_password
、パスワードは使用できないパスワードに設定されています。 -
check_password
(raw_password)与えられたraw_passwordは、ユーザーの実際のパスワードであれば、それはTrueを返し、ユーザーのパスワードを検証する際は、使用することができます。
マネージャの方法:
であるマネージャーのメソッドUser.objects.
メソッド呼び出し。
-
create_user
(ユーザー名、電子メール=なし、パスワード=なし、* * extra_fields)作成し、保存して返す
User
オブジェクトを。 -
create_superuser
(ユーザー名、電子メール、パスワード、* * extra_fields)create_user()
同じですが、設定is_staff
とis_superuser
しますTrue
。
サブユーザのアプリケーションモジュールを作成します。
cd luffyapi/apps/
python ../../manage.py startapp users
settings.pyファイルに登録されているサブアプリケーション。
INSTALLED_APPS = [
...
'users',
]
ユーザ定義のモデルクラスを作成します。
Djangoのモデルクラスのユーザ認証システムおよび方法は非常に便利を提供し、我々はこのモデルクラスを使用できますが、プロジェクトのニーズは、ユーザーの電話番号に保存するよういくつかのフィールドは、プロジェクトのニーズを満たすことができない、あなたはモデルクラスにフィールドを追加する必要があります。
Djangoは提供django.contrib.auth.models.AbstractUser
拡張フィールドを使用Djangoのモデルクラスユーザ認証システム、抽象モデルクラスは、私たちが継承することを可能にするユーザーを。
私たちは、アプリでDjangoアプリケーションのユーザー、設定ファイルの登録ユーザーとアプリケーションを作成することができます。
ユーザーはmodels.pyで良いアプリケーションを作成するために、ユーザモデルクラスを定義します。
from django.db import models
# Create your models here.
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
mobile = models.CharField(max_length=15, unique=True, verbose_name="手机号码")
avatar = models.ImageField(upload_to="avatar", null=True, blank=True, verbose_name="头像")
class Meta:
db_table = 'ly_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
Userモデルは、当社のカスタムクラスが直接Djangoの認証システムを識別することができないと、Djangoを使用した認証システムは、設定ファイルに、当社のカスタムモデルクラスを通知する必要があります。
コンフィギュレーションファイルに設定します
AUTH_USER_MODEL = 'users.User'
AUTH_USER_MODEL
パラメータを設定するために点.
発現され、分離されます应用名.模型类名
。
注:Djangoはそれ以外の不明なエラーがその後の使用を発生することがあり、我々は最初のデータベースの移行が設定される前にAUTH_USER_MODELパラメータがでなければならないために設定されていることを示唆しました。
データベースの移行を実行します
python manage.py makemigrations
python manage.py migrate
実行python manage.py migrate
コマンドを次のようなシステムで与えられます:
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration reversion.0001_squashed_0004_auto_20160611_1202 is applied before its dependency users.0001_initial on database 'default'.
これは、元のモデル廃止されたユーザーを使用して、サブアプリケーションの復帰と呼ばれる男ですが、今のデータベースは、デフォルトのサブアプリケーションとして設定されているusers
モデル、およびその葛藤がありました。したがって、この紛争は、我々は、元のファイルとデータベースの移行が解決することができ、すべての情報をクリアする必要があります。
バックアップデータベース情報
数据库备份 哪一张数据库那一张表(luffy) 库下的表直接点(luffy.)
mysqldump -uroot -p123456 luffy > luffy_2019_12_19.sql
解决步骤:
1. 备份数据库,删除关于用户原来的数据表信息和表结构[如果刚开始开发,则直接清除库中所有数据表即可。
2. 删除apps下面的所有子应用中migrations目录下除了__init__.py以外的所有迁移文件
3. 删除在django.contrib.admin和django.contrib.auth模块里面的migrations迁移文件,除了__init__.py
4. 删除在xadmin和reversion模块中的migrations的迁移文件,除了__init__.py。
5. 执行数据迁移,把备份数据,除了用户以外的全部恢复执行即可。
6. 使用manage.py createsuperuser创建管理员即可
DjangoのRESTフレームワークJWT
ユーザー登録やログインの後、我々はユーザーのログイン状態を記録し、またはユーザの認証証明書を作成したいです。私たちは、もはやJSONウェブトークン認証メカニズムを使用して、セッションの認証メカニズムを使用していません。
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
JWTの憲法
によって文字列のJWT3件の情報情報テキストのこれらの3枚で、構成.
リンクJWT文字列を構成しています。このように:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
我々は頭部(ヘッダ)を呼び出す最初の部分は、第二の部分は、我々は(平面上に担持された商品と同様ペイロード)負荷を呼び出し、および第三の部分は、ビザ(署名)です。
ヘッダ
JWTヘッドは、2つの情報を運びます:
- 宣言された型、ここにJWTがあります
- 暗号化アルゴリズムのアサーションは通常、HMAC SHA256直接使用されます
JSONでこのような完全な頭部:
{
'typ': 'JWT',
'alg': 'HS256'
}
その後、ヘッドbase64で暗号化は、(暗号化は、対称復号化することができる)、第1の部分を構成しています。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
ペイロード
ロードローカルストレージが有効な情報です。名前は、航空機上に担持されたそのような物品に特異的に指し、これらの効果的な情報は、3つの部分から構成され
- 宣言
- 公式声明
- Privateステートメント
標準的な登録届出書(推奨しますが、使用に必須ではありません):
- ISS:JWTの発行者
- サブ:ユーザーのためのJWT
- AUD:受信側JWT
- EXP:JWT有効期限、有効期限は、時間の問題よりも大きくなければなりません。
- NBF:JWTの前に定義されてどのような時間は利用できません。
- IAT:時間の問題JWT
- JTI:JWT独自のアイデンティティは、主にリプレイ攻撃を避けるために、ワンタイムトークンとして使用されています。
Publicステートメント:公共の宣言は任意の情報、必要な情報やその他のビジネスニーズを追加するには、ユーザに関する一般的な情報を追加できますが、機密性の高い情報を追加するために、クライアントの一部を解読することができますので、お勧めしません。
Privateステートメント:base64では、情報の一部が平文として分類することができることを意味し、対称暗号化解除されているため、Privateステートメントは、共通の定義としての文の提供者と消費者であるが、一般的に、機密情報を保存することは推奨されません。
ペイロードを定義します。
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"history": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
}
次いで、JWTの第2の部分を与えるために、base64で暗号化されました。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
署名
JWTは、ビザ情報の第3の部分であり、このビザ情報は、3つの部分からなります:
- (BASE64後)ヘッダ
- ペイロード(BASE64後)
- 秘密
そしてBASE64後のヘッダ部は、base64で使用して暗号化されたペイロードを暗号化する必要が後に.
文字列連結組成物を、その後、塩の暗号化ヘッダによってで宣言されsecret
組合せの暗号化、および第三の部分はJWTを構成しています。
// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
これらの三つの部分.
に接続完全な文字列は、最後のJWTを構成します:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
注:秘密がサーバ側に保存され、サーバー側でも、JWT発生した問題は、秘密はそれはあなたのサーバの秘密鍵であるので、JWTの発行とJWTを認証するために使用され、いずれのシナリオで行くことを明らかにすべきではありません。クライアントが秘密を学習した後は、クライアントが自己署名アップJWTできることを意味します。
jwt的优点:
1. 可以很方便的完成分布式站点的单点登录
2. jwt主要保存在客户端,服务器只需要保存秘钥,所有降低服务器的存储眼里
3. jwt的载荷可以存储一些数据发送给客户端,客户端可以查看对应的载荷中的数据,所以可以用户进行双方数据传输
jwt的缺点:
1. jwt实现比传统的session要复杂
2. jwt的信息保存在客户端,所以一经发放,无法回收。在此过程中,不好控制。保存在客户端部的数据容易被用户操作。
発行し、JWTの検証のために、私たちは完全にDjangoのRESTフレームワークJWT拡張子を使用することができます。
JWTのインストール構成
インストール
pip install djangorestframework-jwt
コンフィギュレーション
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
import datetime
JWT_AUTH = {
# 设置客户端的jwt的exp的有效期为1天
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
}
- JWT_EXPIRATION_DELTAは有効なトークン指定しました
JWTを生成
ドキュメントのDjangoのRESTフレームワークJWT JWTの拡張子によって発行されたマニュアルの方法を提供し、
このコードは、時間内に登録されることに注意してください、我々はに使用されます。
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
ユーザー登録やログインが成功したら、それは未来と可能トークンリターンのシリアライザでユーザー情報を返します。
インタフェースのログイン認証バックエンドの実装
DjangoのRESTフレームワークJWTを直接使用することができ、ログイントークンを取得するビューを提供します
サブアプリケーションでurls.pyにルーティング
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path(r'login/', obtain_jwt_token),
]
メインルートで、現在のサブアプリケーション・ルーティング・ファイルの導入
urlpatterns = [
...
path('users/', include("users.urls")),
# include 的值必须是 模块名.urls 格式,字符串中间只能出现一个圆点
]
次に、我々は郵便配達で、以下の機能をテストすることができます
JWTを保存する2.3.7フロントエンド
我々JWTはクッキーに保存されていることができますはまた、我々はブラウザのローカルストレージに保存され、ブラウザのローカルメモリに格納することができます
ローカルストアブラウザはのsessionStorageとlocalStorageを2つの方法が用意されています。
- sessionStorageのブラウザは消滅する閉じています
- localStorageは、長期的な効果
使用
sessionStorage.变量名 = 变量值 // 保存数据
sessionStorage.setItem("变量名","变量值"); // 保存数据
sessionStorage.变量名 // 读取数据
sessionStorage.getItem("变量名") // 读取数据
sessionStorage.removeItem("变量名") // 删除一个数据
sessionStorage.clear() // 清除所有sessionStorage保存的数据
localStorage.变量名 = 变量值 // 保存数据
localStorage.setItem("变量名","变量值"); // 保存数据
localStorage.变量名 // 读取数据
localStorage.getItem("变量名") // 读取数据
localStorage.removeItem("变量名") // 删除一个数据
localStorage.clear() // 清除所有sessionStorage保存的数据
2.3.9マルチコンディション登録
JWTは、ユーザー名とパスワードを受信したときに、ログインビューを拡張するだけでなく、呼び出し**により提供される認証Djangoの認証システム()**ユーザ名とパスワードが正しい確認します。
私たちは、ユーザー名や電話番号のいずれかとすることができる認証バックエンドDjangoの認証システム(主に認証方式)を変更することで、ログインアカウントをサポートすることができます。
変更の認証バックエンドDjangoの認証システムのニーズはdjango.contrib.auth.backends.ModelBackendを継承し、authenticateメソッドをオーバーライドします。
authenticate(self, request, username=None, password=None, **kwargs)
パラメータ説明方法:
- 要求の認証要求オブジェクト
- ユーザー名のユーザーがこの認定は、提供されたアカウント
- これは、パスワード認証のパスワードを提供します
私たちは、ユーザーがあなたにも、ユーザー名や電話番号ということ、そして、認証方式のため、電話番号にログインするユーザ名パラメータの意味することができ、ユーザ名としてログインいずれかのようにしたいです。
書き換えアイデア認証方法:
- ユーザーのユーザーオブジェクトパラメータのユーザ名を見つけるためによると、ユーザ名パラメータはユーザー名であり、それは電話の数であってもよいです
- それはユーザーオブジェクトを見つけることができた場合は、正しいパスワードユーザオブジェクトかどうかを確認するcheck_passwordメソッドを呼び出します
ユーザー/ utils.py中で書き込み:
# jwt自定义返回函数
def jwt_response_payload_handler(token, user=None, request=None):
"""
自定义jwt认证成功返回数据
:parameter token 本次响应给客户端的jwt字符串
:parameter user 本次查询出来的用户模型对象
:parameter request 本次客户端的请求对象
"""
return {
'token': token,
'id': user.id,
'username': user.username
}
"""自定义用户多条件认证"""
# pycharm自动导包 快捷键: 光标移动到对应的类名中,使用 Alt + Enter
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
def get_account_by_user(username):
"""根据username获取用户信息"""
from .models import User
try:
user = User.objects.get(Q(username=username) | Q(mobile=username))
except User.DoesNotExist:
user = None
return user
class UsernameMobileAuthBackend(ModelBackend):
"""实现用户多条件登录"""
def authenticate(self, request, username=None, password=None, **kwargs):
user = get_account_by_user(username)
if user is not None and user.check_password(password) and user.is_active:
return user
Djangoは、設定ファイルの設定で通知/ dev.py利用当社独自の認証バックエンド
AUTHENTICATION_BACKENDS = [
'users.utils.UsernameMobileAuthBackend',
]