Python - Django authentication system Auth module and Jwt

Login authentication back-end implementation

Django's default authentication system has been provided Auth module. Authentication system includes:

  • User Management
  • Permissions [RBAC]
  • User Group [role group]
  • Password hashing system
  • Users log on or display the content of forms and views
  • A pluggable back-end systems

Django's default user authentication mechanism relies Session mechanism, we introduce JWT authentication mechanism in the project, the identity of the user credentials stored in the Token string, and then docking Django's authentication system, to help us to achieve:

  • User data model
  • User password encryption and authentication
  • User permissions system

Django User model class

Django authentication system provides a user model class User to save the user's data, the default User contain the following common basic fields:

Field name Field Description
username required. 150 characters or less. User names may contain _alphanumeric, @, , + .and -characters.
first_name Optional blank=True( ). Less than equal to 30 characters.
last_name Optional blank=True( ). Less than equal to 30 characters.
email Optional blank=True( ). email address.
password required. Hashed password string. (Django does not save the original password). Original password can be infinitely long and can contain any characters.
groups And Groupmany relationships between.
user_permissions And Permissionmany relationships between.
is_staff Boolean value. Is set Admin users can access the site.
is_active Boolean value. Indicating that the user account is active. It is not used to control whether the user can log in, but describes the use of a state of the account.
is_superuser Whether it is super user. Super User has all the rights.
last_login The last time the user logged in.
date_joined Time accounts created. When the account is created, the default setting is the current date / time.
Common methods:
  • set_password(raw_password)

    Set the user's password to the given raw string, and is responsible for the password. It does not save Userthe object. As Noneis raw_password, the password is set to a password unusable.

  • check_password(raw_password)

    If given raw_password is the user's real password, it returns True, you can use when validating a user password.

Manager method:

Manager method that is by User.objects.method call.

  • create_user(username, email=None, password=None, **extra_fields)

    Create, save and return an Userobject.

  • create_superuser(username, email, password, **extra_fields)

    The create_user()same, but the setting is_staffand is_superuserto True.

Create sub-user application module

cd luffyapi/apps/
python ../../manage.py startapp users

Registered sub-applications in the settings.py file.

INSTALLED_APPS = [
		...
  	'users',
]

Create a user-defined model class

Django model class user authentication system and method provide a very convenient, we can use this model class, but some fields can not meet the needs of the project, as the project needs to be saved in the user's phone number, you need to add additional fields to the model class.

Django provides django.contrib.auth.models.AbstractUserusers an abstract model class allows us to inherit, extended field use Django model class user authentication system.

We can create a Django application users in apps, the registered users and applications in the configuration file.

The user defines the user model classes to create good applications in 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 model our custom class can not directly be identified Django authentication system, an authentication system using Django need to inform our custom model classes in the configuration file.

Set in the configuration file

AUTH_USER_MODEL = 'users.User'

AUTH_USER_MODELSetting parameters to 点.be separated, expressed 应用名.模型类名.

Note: Django suggested that we set for AUTH_USER_MODEL parameters must be before the first database migration is set, otherwise unknown error may occur subsequent use.

Perform a database migration

python manage.py makemigrations
python manage.py migrate

Execute python manage.py migratecommand: given system similar to the following:

django.db.migrations.exceptions.InconsistentMigrationHistory: Migration reversion.0001_squashed_0004_auto_20160611_1202 is applied before its dependency users.0001_initial on database 'default'.

This is a man called reversion of sub-applications using the original model obsolete users, but now the database has been set as the default sub-application usersmodel, and so had a conflict. So this conflict, we need to clear all the information the original files and database migration can be resolved.

Backup database information

数据库备份   哪一张数据库那一张表(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 framework JWT

After the user registration or login, we want to record the user's login status, or create authentication credentials for the user. We no longer use the Session authentication mechanism, use Json Web Token authentication mechanism.

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT's constitution

JWT on a string byThree pieces of informationComposed, with these three pieces of information text .with links constitute Jwt string. like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

The first part we call the head (header), the second part we call the load (payload, similar to items carried on the plane), and the third part is the visa (signature).

jwt head carries two pieces of information:

  • Declared type, here is jwt
  • Assertion of the encryption algorithm is usually used directly HMAC SHA256

Complete head like this in JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

Then the head base64-encryption (the encrypted can be decrypted symmetric), constitutes the first portion.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

payload

Load local storage is valid information. The name refers specifically to such goods carried on the aircraft, these effective information consists of three parts

  • Declaration of
  • Public Statement
  • Private statement

Standard registration statement (recommended, but not mandatory to use):

  • ISS : jwt issuer
  • Sub : JWT for the user
  • AUD : the receiving side jwt
  • exp : jwt expiration time, the expiration date must be greater than the issue of time
  • NBF : What time is defined before the jwt are not available.
  • IAT : jwt the issue of time
  • the JTI : jwt unique identity, is mainly used as a one-time token, in order to avoid a replay attack.

Public statement : public declarations can add any information, general information about the user to add the necessary information or other business needs, but is not recommended for sensitive information to add, because the part of the client can decrypt.

Private statement : Private statement is a statement providers and consumers as common definition, is generally not recommended to store sensitive information, because base64 is decrypted symmetric, meaning that some of the information may be classified as plaintext.

Define a payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "history": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
}

Then base64-encrypted, to give a second portion of the JWT.

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

signature

JWT is the third part of a visa information, this visa information consists of three parts:

  • header (after the base64)
  • payload (after the base64)
  • secret

And after base64 after the header part needs to encrypt the encrypted payload using base64 .string concatenation composition, and then by salt encryption header declared in secretcombination encryption, and the third portion constitutes the jwt.

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

These three parts with .a full string connected, constitutes the final jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Note: secret is stored on the server side, the issue generated jwt also on the server side, secret is used to authenticate the issuance and jwt of jwt, so it is your server's private key, in any scenario should not be revealed to go. Once the client has learned the secret, it means that the client can be self-signed jwt up.

jwt的优点:
1. 可以很方便的完成分布式站点的单点登录
2. jwt主要保存在客户端,服务器只需要保存秘钥,所有降低服务器的存储眼里
3. jwt的载荷可以存储一些数据发送给客户端,客户端可以查看对应的载荷中的数据,所以可以用户进行双方数据传输

jwt的缺点:
1. jwt实现比传统的session要复杂
2. jwt的信息保存在客户端,所以一经发放,无法回收。在此过程中,不好控制。保存在客户端部的数据容易被用户操作。

For issuing and verification of JWT, we can use Django REST framework JWT extension to complete.

Documentation Website

JWT installation configuration

installation

pip install djangorestframework-jwt

Configuration

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 specified token valid

Generate jwt

Django REST framework JWT extension of the documentation provides a method of manual issued by JWT

Note that this code will be registered in time, we will use to.

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)

After the user registration or login is successful, it returns the user information in the serializer in the future and returns token can be.

Interface login authentication back-end implementation

Django REST framework JWT provides a view of obtaining login token can be used directly

In sub-application routing in urls.py

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    path(r'login/', obtain_jwt_token),
]

In the main routes, the introduction of the current sub-application routing file

urlpatterns = [
		...
    path('users/', include("users.urls")),
    # include 的值必须是 模块名.urls 格式,字符串中间只能出现一个圆点
]

Next, we can test the following functions by postman

2.3.7 front-end to save jwt

We can JWT saved in a cookie can also be stored in the local memory of the browser, we saved in the browser local storage

Local store browser provides sessionStorage and localStorage two ways:

  • sessionStorage browser is closed shall lapse
  • localStorage long-term effective

Instructions

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 multi-condition registering

JWT extended login view, when you receive a user name and password, but also call ** authenticate Django's authentication system provided by () ** to check the user name and password are correct.

We can support the login account by modifying the authentication backend Django authentication system (primarily authenticate method) can be either a user name or a phone number.

Modify authentication backend Django authentication system needs to inherit django.contrib.auth.backends.ModelBackend, and override the authenticate method.

authenticate(self, request, username=None, password=None, **kwargs)Parameter Description method:

  • The request authentication request object
  • username user account this certification provided
  • This provides password authentication password

We want to let users either log in as the user name, you can also log in to the phone number, then for the authenticate method, username parameter means that the user name or phone number.

Rewrite ideas authenticate method:

  1. According to locate the user User object parameter username, the username parameter may be a user name, it may be the phone number
  2. If it can find the User object, call check_password method to check whether the correct password User object

Write in users / utils.py in:

# 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 informed in the configuration file settings / dev.py use our custom authentication backend

AUTHENTICATION_BACKENDS = [
    'users.utils.UsernameMobileAuthBackend',
]

Guess you like

Origin www.cnblogs.com/zhaoganggang/p/12570819.html