• authenticate验证的流程


     流程简单梳理

    - 入口
    from django.contrib.auth import authenticate
    user = authenticate(username=cd['username'], password=cd['password'])
    # If the given credentials are valid, return a User object.
    
    	- 获取全部用于认证的backend
    	settings.AUTHENTICATION_BACKENDS
    	Default: ['django.contrib.auth.backends.ModelBackend']
    	# https://docs.djangoproject.com/en/1.11/ref/settings/#auth
    
    	- 遍历全部backend并执行认证操作
    	user = _authenticate_with_backend(backend, backend_path, request, credentials)
    	# credentials: { 'username':'xxx', 'password':'xxx' }
    	默认只有ModelBackend这个backend,认证是通过调用这个类里的authenticate函数
    		- 通过username查找出user对象
    		- user.check_password(password)
    		    # django.contrib.auth.base_user.AbstractBaseUser
    			- AbstractBaseUser.check_password(self, raw_password)
    				- django.contrib.auth.hashers.check_password(raw_password, self.password, setter)
    					- 获取settings.PASSWORD_HASHERS里的第一个hash算法
    					  默认是 django.contrib.auth.hashers.PBKDF2PasswordHasher
    					- 根据self.password来找到当前用户的密码采用的hash算法
    					- 判断用户密码采用的hash算法和当前默认的第一hash算法是否相同 (暂且只考虑相同的情况)
    					- 把用户密码拆分成:algorithm, iterations, salt, hash,用iterations和hash算法的iterations做对比是否一致
    					- 验证:hasher.verify(password, encoded)
    						- 把用户输入的密码进行加密:先用hashlib.sha256,然后在用base64.b64encode最终计算出一个hash值
    						- 然后把 self.algorithm, iterations, salt, hash 组合成一个字符串,记作encoded_2
    						- 把用户真实密码和encoded_2作比较,看看是否相同
    		- user_can_authenticate(user)
    			- 判断当前用户的 is_active

     

    from django.contrib.auth import authenticate

    # 默认的第一个加密算法

    class PBKDF2PasswordHasher(BasePasswordHasher):
        """
        Secure password hashing using the PBKDF2 algorithm (recommended)
    
        Configured to use PBKDF2 + HMAC + SHA256.
        The result is a 64 byte binary string.  Iterations may be changed
        safely but you must rename the algorithm if you change SHA256.
        """
        algorithm = "pbkdf2_sha256"
        iterations = 36000
        digest = hashlib.sha256
    
        def encode(self, password, salt, iterations=None):
            assert password is not None
            assert salt and '$' not in salt
            if not iterations:
                iterations = self.iterations
            hash = pbkdf2(password, salt, iterations, digest=self.digest)
            hash = base64.b64encode(hash).decode('ascii').strip()
            return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
    
        def verify(self, password, encoded):
            algorithm, iterations, salt, hash = encoded.split('$', 3)
            assert algorithm == self.algorithm
            encoded_2 = self.encode(password, salt, int(iterations))
            return constant_time_compare(encoded, encoded_2)
    
        def safe_summary(self, encoded):
            algorithm, iterations, salt, hash = encoded.split('$', 3)
            assert algorithm == self.algorithm
            return OrderedDict([
                (_('algorithm'), algorithm),
                (_('iterations'), iterations),
                (_('salt'), mask_hash(salt)),
                (_('hash'), mask_hash(hash)),
            ])
    
        def must_update(self, encoded):
            algorithm, iterations, salt, hash = encoded.split('$', 3)
            return int(iterations) != self.iterations
    
        def harden_runtime(self, password, encoded):
            algorithm, iterations, salt, hash = encoded.split('$', 3)
            extra_iterations = self.iterations - int(iterations)
            if extra_iterations > 0:
                self.encode(password, salt, extra_iterations)

    from django.contrib.auth.hashers import make_password

    def make_password(password, salt=None, hasher='default'):
        """
        Turn a plain-text password into a hash for database storage
    
        Same as encode() but generates a new random salt.
        If password is None then a concatenation of
        UNUSABLE_PASSWORD_PREFIX and a random string will be returned
        which disallows logins. Additional random string reduces chances
        of gaining access to staff or superuser accounts.
        See ticket #20079 for more info.
        """
        if password is None:
            return UNUSABLE_PASSWORD_PREFIX + get_random_string(UNUSABLE_PASSWORD_SUFFIX_LENGTH)
        hasher = get_hasher(hasher)
    
        if not salt:
            salt = hasher.salt()
    
        return hasher.encode(password, salt)

    from django.contrib.auth.hashers import check_password

    def check_password(password, encoded, setter=None, preferred='default'):
        """
        Returns a boolean of whether the raw password matches the three
        part encoded digest.
    
        If setter is specified, it'll be called when you need to
        regenerate the password.
        """
        if password is None or not is_password_usable(encoded):
            return False
    
        preferred = get_hasher(preferred)
        hasher = identify_hasher(encoded)
    
        hasher_changed = hasher.algorithm != preferred.algorithm
        must_update = hasher_changed or preferred.must_update(encoded)
        is_correct = hasher.verify(password, encoded)
    
        # If the hasher didn't change (we don't protect against enumeration if it
        # does) and the password should get updated, try to close the timing gap
        # between the work factor of the current encoded password and the default
        # work factor.
        if not is_correct and not hasher_changed and must_update:
            hasher.harden_runtime(password, encoded)
    
        if setter and is_correct and must_update:
            setter(password)
        return is_correct

    authenticate在处理用户登录验证时候的过程

    import os
    os.environ.setdefault('DJANGO_SETTINGS_MODULE','django_auth.settings')
    
    from django.contrib.auth.hashers import (
        check_password, is_password_usable, make_password,
    )
    
    
    if __name__ == '__main__':
        raw_password = 'Qr3!JQc9bU@hrs2qjdqaE'
        password = make_password(raw_password)
    
    
        print(password)
    
    
        from django.conf import settings
        # print(settings.AUTHENTICATION_BACKENDS) # django.contrib.auth.backends.ModelBackend
        from django.utils.module_loading import import_string
    
        # for backend_path in settings.AUTHENTICATION_BACKENDS:
        #     backend = import_string(backend_path)()
        #     print(backend_path,backend)
    
        hashers_lst = settings.PASSWORD_HASHERS
        '''
        [
            'django.contrib.auth.hashers.PBKDF2PasswordHasher', 
            'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 
            'django.contrib.auth.hashers.Argon2PasswordHasher', 
            'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 
            'django.contrib.auth.hashers.BCryptPasswordHasher']
        '''
        preferred = import_string(hashers_lst[0])()
        # <django.contrib.auth.hashers.PBKDF2PasswordHasher object at 0x0000000000B3BAC8>
        print(preferred.algorithm)
        from django.contrib.auth import hashers
        encoded = 'pbkdf2_sha256$36000$0EDgzLtVVT7o$nWQ4t3+iWKzv9p6MUfNIQPazaasadhYUtKt2ubLRCTA='
        hasher = hashers.identify_hasher(encoded)
        # <django.contrib.auth.hashers.PBKDF2PasswordHasher object at 0x0000000000BB8978>
        print(hasher.algorithm)  # pbkdf2_sha256
    
        hasher_changed = hasher.algorithm != preferred.algorithm
    
        print(hasher_changed) # False
    
        is_correct = hasher.verify(raw_password, encoded)
        print(is_correct)
    
        algorithm, iterations, salt, hash = encoded.split('$', 3)
        print(algorithm, iterations, salt, hash)
        encoded2 = hasher.encode(raw_password, salt, int(iterations))
        print(encoded2)
    

    看源码,打印输出,是接近真相最便捷的途径。  

  • 相关阅读:
    15第十四章:Docker轻量级可视化工具Portainer
    14第十三章:Dockercompose容器编排
    01第一章:【01】设计模式前言
    16第十五章:Docker容器监控
    13第十二章:Docker网络
    00设计模式【目录】
    03第一章:【02】单一职责原则(SRP)
    12第十一章:Docker微服务实战
    02第一章:【01】设计模式七大原则
    node2vec: Scalable Feature Learning for Networks
  • 原文地址:https://www.cnblogs.com/standby/p/9208884.html
Copyright © 2020-2023  润新知