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)
看源码,打印输出,是接近真相最便捷的途径。
authenticate验证的流程的更多相关文章
- https申请证书并部署到网站流程,浏览器验证证书流程
https申请证书并部署到网站流程: 1.生成一对秘钥,设公钥为pubk1,私钥为prik12.假设发布的网站地址为https://www.example.com3.生成一个CSR文件(Cerific ...
- Token验证的流程及如何准确的判断一个数据的类型
Token验证的流程: 1,客户端使用用户名跟密码请求登录:2,服务端收到请求,去验证用户名与密码:3,验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端:4,客户端收到 T ...
- authenticate的执行流程与重写
流程 1.authenticate调用的是_get_backends函数 def authenticate(request=None, **credentials): for backend, bac ...
- springcloud +spring security多种验证方式之第三方token生成自己的token通过校验和自己的表单验证大体流程
步骤: 1.继承 WebSecurityConfigurerAdapter.class,其中使用两个过滤器,一个spring scurity自带的UsernamePasswordAuthenticat ...
- Shiro -- (二) 身份验证基本流程
简介: 在 shiro 中,用户需要提供 principals (身份)和 credentials(证明)给 shiro,从而应用能验证用户身份: principals:身份,即主体的标识属性,可以是 ...
- Apache shiro之身份验证(登陆)流程
从张开涛blog学习后整理:http://jinnianshilongnian.iteye.com/blog/2018398 上图中的类和接口都可以继承和实现来个性化自己的实现. 其中重点看一下Mod ...
- SharePoint2010 Form验证配置流程
1.修改管理中心的Web.config文件,位置:C:\inetpub\wwwroot\wss\VirtualDirectories\42903 2.修改应用程序的Web.config文件,位置:C: ...
- 【ASP.NET】编程点滴 :ASP.NET身份验证
ASP.NET实际开发中身份验证 是一个不可回避的问题.在相当一段长的时间内,由于不求甚解,我对这个话题似懂非懂.今天就对它做个简单的小结. Authentication and Authorizat ...
- ASP.NET Forms身份验证概述
表单身份验证允许您使用自己的代码对用户进行身份验证,然后在cookie或页面URL中维护身份验证令牌.表单身份验证通过FormsAuthenticationModule类参与ASP.NET页面生命周期 ...
随机推荐
- 【cf789D】Weird journey(欧拉路、计数)
cf788B/789D. Weird journey 题意 n个点m条边无重边有自环无向图,问有多少种路径可以经过m-2条边两次,其它两条边1次.边集不同的路径就是不同的. 题解 将所有非自环的边变成 ...
- poj3926 parade (单调队列+dp)
题意:有n行路,每行路被分成m段,每一段有长度和权值,要求从最下面一行走到最上面一行某个位置,可以从相邻两行的同一列交点往上走,并且在同一行走的长度要<=K,求走过的最大权值 设f[i][j]为 ...
- 【Linux】linux正则表达式及通配符
正则表达式就是用于匹配每行输入的一种模式,模式是指一串字符序列.拥有强大的字符搜索功能.也非常方便的搜索过滤出我们想要的内容. linux正则表达式分为基本正则表达式(Basic Regexp)和扩展 ...
- centos7安装mysql5.6(rpm包安装)
应用场景:日常需求安装数据库——MySQL. 安装环境:① 最小化安装的centos7.2(同版本RHEL7适用): ② MySQL 5.6: 具体步骤: 1. 下载mysql 5.6并解压(官网有时 ...
- tyvj/joyoi 1340 送礼物
论搜索顺序的优越性. 从小到大搜索,T到怀疑人生. 从大到小搜索,轻松AC. 双向搜索. 是这样的.我们首先排序一下,然后翻转.(当然也可以写cmp) 然后我们搜前半部分,把结果记录在某一数组中. 然 ...
- 洛谷P2150 寿司晚宴
解:发现每个质数只能属于一个人,于是想到每个质数有三种情况:属于a,属于b,都不属于. 然后考虑状压每个人的质数集合,可以得到30分. 转移就是外层枚举每个数,内层枚举每个人的状态,然后看能否转移.能 ...
- bzoj2839 集合计数
F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser Logout 捐赠本站 2839: 集合计数 Time ...
- Mac 软件专题:高效率工作和学习工具软件推荐
今天和大家分享软件专题:「高效率工作和学习工具」,简而言之就是提高你工作和学习效率的软件,这对于要天天使用Mac工作或学习的人来说太有帮助了,这里主要分享大家平时经常用的一些,欢迎留言补充. 本文图片 ...
- Java 中的悲观锁和乐观锁的实现
一.定义 1.悲观锁:即很悲观,每次拿数据的时候都觉得数据会被人更改,所以拿数据的时候就把这条记录锁掉,这样别人就没法改这条数据了,一直到你的锁释放. 2.乐观锁:即很乐观,查询数据的时候总觉得不会有 ...
- SpringCloud之注册中心Eureka搭建
POM: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring ...