django自定义用户认证_用户自定义的类

django自定义用户认证_用户自定义的类前言如果我们不用使用drf那套认证规则,我们想自定义认证类,那么我们首先要知道,drf本身是如何定义认证规则的,也就是要查看它的源码是如何写的源码分析源码的入口在APIView.py文件下的di

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

如果我们不用使用drf那套认证规则,我们想自定义认证类,那么我们首先要知道,drf本身是如何定义认证规则的,也就是要查看它的源码是如何写的
 

源码分析

源码的入口在APIView.py文件下的dispatch方法下的self.initial方法中的self.perform_authentication(request),点击查看后如下

  def perform_authentication(self, request):
      """
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
      """
      request.user

返回了一个requestuser方法,request代表的是drfRequest,所以我们进入drfRequest类中查找user方法属性,源码如下:

    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

上述代码的意思是:返回与当前请求关联的用户,由提供给请求的身份验证类进行身份验证。如果没有用户,我们需要通过_authenticate方法验证,我们查看下它的源码

def _authenticate(self):
    """
    尝试依次使用每个身份验证实例对请求进行身份验证。
    """
    for authenticator in self.authenticators:
        try:
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise

        if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return

    self._not_authenticated()

我们可以看到self.authenticators验证器其实是调用父类APIViewauthenticatorsAPIViewauthenticators在源码initialize_request方法下的get_authenticators,我们查看源码

def get_authenticators(self):
    """
    Instantiates and returns the list of authenticators that this view can use.
    """
    return [auth() for auth in self.authentication_classes]

再点击authentication_classes查看

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

我们就知道了drf默认的认证器在settings文件下的DEFAULT_AUTHENTICATION_CLASSES类下面

'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    ],

我们发现drf默认有2个认证类一个基础的认证,另一个session认证,这两个认证类都继承自BaseAuthentication,我们来看下源码

class BaseAuthentication:
    """
    所有的认证类都继承自BaseAuthentication.
    """

    def authenticate(self, request):
        """
         认证请求返回一个二元组(user, token),并且此方法必须重写,否则抛出异常
        """
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        """
        pass

接下来我们看下BasicAuthentication如何写的,后续我们依葫芦画瓢

class BasicAuthentication(BaseAuthentication):
    """
    针对用户名密码的 HTTP 基本身份验证
    """
    www_authenticate_realm = 'api'

    def authenticate(self, request):
        """
        如果使用 HTTP 基本身份验证提供了正确的用户名和密码,则返回“User”。否则返回“None”。
        """
        # 获取请求头中`HTTP_AUTHORIZATION`,并进行分割
        auth = get_authorization_header(request).split()
        
        # 如果没有auth或者auth的第一个索引值的小写不等于basic,则返回None
        if not auth or auth[0].lower() != b'basic':
            return None
        
        # auth列表的长度必须等于2,格式['basic', 'abc.xyz.123']
        # 如果auth的长度等于1,则抛出异常
        if len(auth) == 1:
            msg = _('Invalid basic header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        # 如果长度大于2,也抛出异常
        elif len(auth) > 2:
            msg = _('Invalid basic header. Credentials string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            try:
                # auth[1]解码格式为utf-8
                auth_decoded = base64.b64decode(auth[1]).decode('utf-8')
            except UnicodeDecodeError:
                auth_decoded = base64.b64decode(auth[1]).decode('latin-1')
            auth_parts = auth_decoded.partition(':')
        except (TypeError, UnicodeDecodeError, binascii.Error):
            msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
            raise exceptions.AuthenticationFailed(msg)

        userid, password = auth_parts[0], auth_parts[2]
        return self.authenticate_credentials(userid, password, request)

    def authenticate_credentials(self, userid, password, request=None):
        """
        Authenticate the userid and password against username and password
        with optional request for context.
        """
        credentials = {
            get_user_model().USERNAME_FIELD: userid,
            'password': password
        }
        user = authenticate(request=request, **credentials)

        if user is None:
            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

        if not user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        return (user, None)

    def authenticate_header(self, request):
        return 'Basic realm="%s"' % self.www_authenticate_realm

 

自定义认证类

  1. 创建继承BaseAuthentication的认证类
  2. 实现authenticate方法
  3. 实现体根据认证规则 确定 游客 正常用户 非法用户
  4. 进行全局或局部配置(一般采用全局配置)

认证规则

  1. 没有认证信息,返回None(游客)
  2. 有认证信息认证失败,抛异常(非法用户)
  3. 有认证信息认证成功,返回用户和认证信息的元组(合法用户)

我们创建一个文件夹authentications,写入如下代码

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from api.models import User


class MyAuthentications(BaseAuthentication):

    def authenticate(self, request):
        # 前台在请求头携带认证信息
        # 且默认规范用Authorization字段携带认证信息
        # 后台固定在请求对象的META字段中的HTTP_AUTHORIZATION获取
        auth = request.META.get('HTTP_AUTHORIZATION', None)

        # 处理游客
        if auth is None:
            return None

        auth_list = auth.split()
        if not len(auth_list) == 2 and auth_list[0].lower() == "auth":
            raise AuthenticationFailed("认证信息有误,非法用户")
        # 合法的用户还需要从auth_list[1]中解析出来
        # 注:假设一种情况,信息为xx.yy.zz,就可以解析出admin用户:实际开发,该逻辑一定是校验用户的正常逻辑
        if auth_list[1] != 'xx.yy.zz':  # 校验失败
            raise AuthenticationFailed("用户校验失败,非法用户")

        user = User.objects.filter(username='jkc').first()
        print(user)

        if not user:
            raise AuthenticationFailed("用户数据有误,非法用户")

        return user, None

然后在settings.py中配置全局的自定义认证类

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'api.authentications.MyAuthentications'
    ],
}

最后写入视图函数

class TestView(APIView):
    def get(self, request, *args, **kwargs):
        return APIResponse(data_msg="drf get ok")

然后我们访问视图,在headers中不传Authorization 代表游客,游客可以访问成功

{
    "statusCode": 0,
    "message": "drf get ok"
}

接着我们在请求头中只传auth
django自定义用户认证_用户自定义的类
访问视图会抛出异常信息

{
    "detail": "认证信息有误,非法用户"
}

然后我们在请求头中传入错误的认证,auth 111
django自定义用户认证_用户自定义的类
访问视图会抛出异常信息

{
    "detail": "用户校验失败,非法用户"
}

最后我们在请求头中传入正确的认证,auth xx.yy.zz,这次会得到正确的返回结果

{
    "statusCode": 0,
    "message": "drf get ok"
}

以上的测试,就代表我们自定义的认证类起作用了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/165416.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 信息熵和基尼系数_信息熵和基尼系数

    信息熵和基尼系数_信息熵和基尼系数一、基尼系数是什么?1)定义    下面是摘自李航《统计学习方法》中基尼系数的定义,非常清晰。2)基尼系数有什么意义?    我们可以先来看一组数据X的取值 方案一 方案二 方案三 方案四 P的平方 方案一 方案二 方案三 方案四类别一 0.9 0.5 0.4 0.2 p1^2 0.81 0.25 0.16 0.04类别二 0.1 0.5 0.3 0.2 p2^2 0.01 0.25 0.09 0…

    2022年10月10日
  • 安卓性能调优:内存使用分析和方法调用优化

    安卓性能调优:内存使用分析和方法调用优化

  • RapidXML的读写

    RapidXML的读写把如下图几个文件放到工程目录(hpp文件)新建工程进行读写测试,代码如下://ConsoleApplication1.cpp:定义控制台应用程序的入口点。//#include”stdafx.h”#include”rapidxml.hpp”#include”rapidxml_utils.hpp”//rapidxml::file#include”rapidx…

  • 银行风控模型

    银行风控模型风控催生原因对于银行来说,现今互联网贷款和信用卡办理面临的主要难题是数据和风控。站在银行或金融机构角度,自然而然是想获得更多的信息和数据,但是在收集数据这方面又是比较无力的。加上当下的发展趋势,消费贷以及贷款审批速度都要求快。如何在快的的过程中对客户进行一个全面的审查,得出一个合理的结果呢?如果没有详细的数据对客户进行评估,这势必会提高放贷的风险。风控概述所谓风控,是指多银行贷款资金的…

  • PyCharm激活码永久有效PyCharm2018.1.4激活码教程-持续更新,一步到位

    PyCharm激活码永久有效PyCharm2018.1.4激活码教程-持续更新,一步到位PyCharm激活码永久有效2018.1.4激活码教程-Windows版永久激活-持续更新,Idea激活码2018.1.4成功激活

  • ftp免费下载工具,4个好用的ftp免费下载工具

    ftp免费下载工具,4个好用的ftp免费下载工具ftp免费下载工具主要是网络上用来传送文件的工具。但有些ftp免费下载工具传输文件不是特别稳定。今天就来为大家分享4款站长们都爱用的ftp免费下载工具。第一款:IIS7服务器管理工具这款软件的Ftp客户端做的是非常棒的,不仅具有批量操作功能,还具有定时同步(上传和下载)和自动更新功能。这些功能真的是我超爱的功能,做事效率提高了不止一星半点。而且特别容易上手,一般的软件都还需要熟悉一下,这个就是很快的能开始运用。好处很多,需要用户慢慢去体会。有的东西是只能亲身体验过后才知道的。IIS7服务器管理工具所包

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号