机遇总是有的,如果把握不住,不要怨天忧人,只因自己不够优秀;不要把时间当垃圾处理,唯有珍惜光阴,才能提升生命的质量!
总结:
- 用户注册登录名重复怎么解决;
- 如何对密码进行加密;
- 如果要发一些数据发送到第三方客户端,有没有第三种解决方案jwt(防篡改);
密码
使用邮箱 + 密码方式登录。
邮箱要求唯一就行了,但是,密码如何存储?
早期,都是明文的密码存储。
后来,使用MD5存储,但是,目前也不安全,网上有很多MD5的网站,使用反查方式找到密码。
加盐,使用hash(password + salt)的结果存入数据库中,就算拿到数据库的密码反查,也没有用了。如果是固定加盐,还是容易被找到规律,或者从源码中泄露。随机加盐,每一次盐都变,就增加了破解的难度。
暴力破解, 什么密码都不能保证不被暴力破解, 例如穷举。所以要使用慢hash算法, 例如b crypt, 就会让每一次计算都很慢, 都是秒级的, 这样穷举的时间就会很长,为了一个密码破解的时间在当前CPU或者GPU的计算能力下可能需要几十年以上;
BCrypt
BCrypt加密算法,号称目前最安全的算法之一
哈希(Hash)是将目标文本转换成具有相同长度的、不可逆的杂凑字符串(或叫做消息摘要),而加密(Encrypt)是将目标文本转换成具有不同长度的、可逆的密文。
pip install bcrypt
哈希算法,32位,往往被设计成生成具有相同长度的文本,而加密算法生成的文本长度与明文本身的长度有关。哈希算法是不可逆的,而加密算法是可逆的。
从耗时看出, b crypt加密、验证非常耗时, 所以如果穷举, 非常耗时。而且碰巧攻破一个密码, 由于盐不一样, 还得穷举另一个;
salt=b'$2b$12$jwBD7mg9stvIPydF2bqoPO'
b'$2b$12$jwBD7mg9stvIPydF2bqoPOod PwW YV vdmZb5uwWuwvlf9iHqNlKSQO'
$是分隔符
$2b$,加密算法
12, 表示2^12key expansion rounds
这是盐b'jwBD7mg9stvIPydF2bqoPO', 22个字符, Base 64
这是密文b'odP wWYVvdmZb5uwWuwvlf9iHqNl KS QO', 31个字符, Base 64
import bcrypt
import datetime
password = b'123456'
# 每次拿到盐都不一样
print(1, bcrypt.gensalt())
print(2, bcrypt.gensalt())
salt = bcrypt.gensalt()
# 拿到的盐相同,计算等到的密文相同
print('=========same salt ==========')
x = bcrypt.hashpw(password, salt)
print(3, x)
x = bcrypt.hashpw(password, salt)
print(4, x)
# 每次拿到的盐不同,计算生成的密文也不一样
print('=========different salt ==========')
x = bcrypt.hashpw(password, bcrypt.gensalt())
print(5, x)
x = bcrypt.hashpw(password, bcrypt.gensalt())
print(6, x)
# 校验
print(bcrypt.checkpw(password, x), len(x))
print(bcrypt.checkpw(password + b' ', x), len(x)) # 错误校验方法;
# 计算时长
start = datetime.datetime.now()
y = bcrypt.hashpw(password, bcrypt.gensalt())
delta = (datetime.datetime.now() - start).total_seconds()
print(10, 'duration={}'.format(delta))
# 检验时长
start = datetime.datetime.now()
y = bcrypt.checkpw(password, x)
delta = (datetime.datetime.now() - start).total_seconds()
print(y)
print(11, 'duration={}'.format(delta))
start = datetime.datetime.now()
y = bcrypt.checkpw(b'1', x)
delta = (datetime.datetime.now() -start).total_seconds()
print(y)
print(10, 'duration={}'.format(delta))
注册代码 V2
全局变量
项目的settings.py文件实际上就是全局变量的配置文件。
SECRET_KEY 一个强密码
from django.http import JsonResponse,HttpRequest,HttpResponseBadRequest
import simplejson,jwt,bcrypt
from .models import User
from django.db.models import Q
from django.conf import settings
def gen_token(user_id): # 生成令牌;
key = settings.SECRET_KEY
return JsonResponse({
'token':jwt.encode({'user_id':user_id},key,'HS256').decode()
},status=201)
# register
def reg(request:HttpRequest):
print(request.body)
try:
payload = simplejson.loads(request.body) # 用户数据Json化 提交;
print(type(settings))
email = payload['email'] # 提取内容
query = User.objects.filter(email=email) # 看email是否已经存在;
if query.first(): # 查一下: email 如果存在,则return error;
print('============================')
return HttpResponseBadRequest('用户名已存在')
# 用户名不存在,继续向下;
name = payload['name'] #
password = payload['password']
user = User()
user.email = email
user.name = name
user.password = bcrypt.hashpw(password.encode(),bcrypt.gensalt()) # 密码采用bcrypt加密;
try:
user.save() #保存到数据库test,唯一键约束
return gen_token(user.id) # 保存数据后返回一个令牌数据回去;
# 可以返回user_id status=201(注册成功 重新登录) 或者 token(登录)
except Exception as e:
return JsonResponse({'reason':'asdaf'},status=400)
except Exception as e:
print(e)
return HttpResponseBadRequest('参数错误')
def show(request): # 方法的使用方式各不相同;
users = User.objects.all()
print(users.values())# objects
return JsonResponse({})
# postman---------------------------------------------------------
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5fQ._qB1j7cV-TIe5nZY8yO_x0e3xsnPQef-_1SRcQM-3_k"
}
网友评论