Django 认证流程源码分析以及自定义 Backend(超详细)

默认认证

django 有自己的认证方法,不过是基于用户名密码(根据自然键 USERNAME_FIELD的方式,实现简单的认证方式,如下:

from django.contrib.auth import login as auth_login

def login(request):
	# 最主要在 authenticate 里面
    user = authenticate(request, **request.POST)
    if not user:
        return JsonResponse({"message":"登录失败"})

    auth_login(request, user)

    return JsonResponse({"message": "success"})

authenticate 源码

循环每一个 backend,执行里面的 authenticate 方法,该方法一定要实现。

def authenticate(request=None, **credentials):
    """
    If the given credentials are valid, return a User object.
    """
    # 循环每一个认证方式,返回一个认证好的 user 对象
    # _get_backends,是 settings.py 中AUTHENTICATION_BACKENDS 列表里面定义的认证方式
    # 如果没有定义就用默认的认证方式
    for backend, backend_path in _get_backends(return_tuples=True):
        try:
            inspect.getcallargs(backend.authenticate, request, **credentials)
        except TypeError:
            # This backend doesn't accept these credentials as arguments. Try the next one.
            continue
        try:
        	# 不管是内置的还是自定义的,每个 backend 都要实现一个 authenticate
        	# authenticate 里面是自己编写好的认证逻辑
            user = backend.authenticate(request, **credentials)
        except PermissionDenied:
            # This backend says to stop in our tracks - this user should not be allowed in at all.
            break
        if user is None:
            continue
        # Annotate the user object with the path of the backend.
        user.backend = backend_path
        return user
	
	# 如果所有认证都没有通过,发射信号
    # The credentials supplied are invalid to all backends, fire signal
    user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)

默认的认证方式:
没有定义 AUTHENTICATION_BACKENDS ,那么去哪里找它用了那个 backend 呢,可以去全局去找,里面肯定有默认的 backend。

from django.conf import settings

global_settings.py

AUTH_USER_MODEL = 'auth.User'

AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']

ModelBackend:
导入它,进去看:from django.contrib.auth.backends import ModelBackend

from django.contrib.auth.backends import ModelBackend

class ModelBackend:
    """
    Authenticates against settings.AUTH_USER_MODEL.
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
        	# 通过自然键(USERNAME_FIELD)获取 user 对象 
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
        	# 检查密码和是否是活跃用户,然后返回一个 user 对象,否则什么也不返回 就是 None
            if user.check_password(password) and self.user_can_authenticate(user):
                return user

自定义 Backend

为什么自定义 backend, 这里只支持用户名(根据 USERNAME_FIELD 设置的字段) 来认证,如果有其他的方式 django 是没办法支持,比如验证码登录、微信登录、token登录(drf支持)、LDAP登录,这些不太好支持,需要自定义一些认证来实现。

from django.contrib.auth.backends import BaseBackend

""""
一般要继承 BaseBackend 然后实现 authenticate,但 django 4.0 以前是不用的,
就是可以不用继承 BaseBackend,直接实现就行,或者继承 ModeBackend, 覆盖里面的
authenticate 和 user_can_authenticate,根据自己需求。
"""

class PasswordBackend(BaseBackend):
     def authenticate(self, request, method, **kwargs):
     	# 密码登录
     	if method != 'password':
            return None

class OtpCodeBackend(BaseBackend):
     def authenticate(self, request, method, **kwargs):
     	# 短信验证码登录
     	if method != 'otpcode':
            return None

class WechatBackend(BackendBase):
    def authenticate(self, request, method, **kwargs):
        if method != 'wechat':
            return None

settings.py 中:
AUTHENTICATION_BACKENDS = [
	# 自己自定义 backend 的路径
	'app01.account.backends.PasswordBackend',
	'app01.account.backends.OtpCodeBackend',
	'app01.account.backends.WechatBackend',
]

参考文献

django 官网:https://docs.djangoproject.com/zh-hans/4.0/topics/auth/customizing/
django 自带的 auth 认证系统:https://blog.csdn.net/qq_39253370/article/details/108464419?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165460504816781818740619%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165460504816781818740619&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-108464419-null-null.article_score_rank_blog&utm_term=auth&spm=1018.2226.3001.4450

你可能感兴趣的:(python,orm,django,python,后端,drf,权限)