文章目录
用户功能设计与实现
用户注册接口设计
接受用户通过post方法提交的注册信息。提交格式为json数据
检查email是否已存在与数据库表中,如果存在。返回错误状态码,不存在将用户提交的数据存入表中
整个过程是resful风格,前后端分离:必须约定好url和接口(各开发各的)
路由设置
from django.conf.urls import url,include
from django.contrib import admin
from django.http import HttpResponse,HttpRequest,JsonResponse
from django.template import loader
from django.template.backends.django import Template
from django.shortcuts import render #快捷方式
def index(request): #这就是wsgi app的函数 只不过environ,start_response这两个参数给我们封装好了只需要request就行了
# template:Template = loader.get_template('index.html')
# print(type(template),'!!!!!',template.origin)
# print(template.render({},request))
return render(request,'index.html',{
'a':['{}*{}={}'.format(i,j,i*j) for i in range(1,10) for j in range(1,10)],
'b':list(range(1,10)),
'd':list(range(10,20))
})
from user.views import reg
urlpatterns = [
url(r'^admin/', admin.site.urls), #管理后面 正则表达式(路劲) 后面视图函数
url(r'^index',index), #首页
url(r'^user/', include('user.urls')) #user目录下的子目录
]
将url/user/* 映射到user/的urls
user/urls.py
from django.conf.urls import url
from django.http import HttpResponse,HttpRequest,JsonResponse
from django.shortcuts import render #快捷方式
from user.views import reg
urlpatterns = [
url(r'',reg)
]
user/views.py
from django.shortcuts import render
from django.http import HttpResponse,HttpRequest
# Create your views here.
def reg(request:HttpRequest):
return HttpResponse(b'user')
CSRF处理
这里我用的是postman,想做实验的可以下载
在post提交时,需给服务器发送一个csrf_token
解决方法有两个:
1.关闭中间件里的csrf验证(不推荐)
2.在模板的表单里加一个{% csrf_token %},它返回浏览器端会给cookie增加csrftoken字段,如果使用ajax进行post,需要在请求header中增加X-CSRFTOKEN
先用get请求index,获取csrftoken的值,在post的params里加入就可以访问成功了
先下载simplejson的包
pip install simplejson
from django.shortcuts import render
from django.http import HttpResponse,HttpRequest
import simplejson
# Create your views here.
def reg(request:HttpRequest):
# print(request.body)
payload = simplejson.loads(request.body)
print(payload)
return HttpResponse(b'user')
postman发起请求
用户注册
from django.shortcuts import render
from django.http import HttpResponse,HttpRequest,HttpResponseBadRequest
import simplejson
from .models import User
# Create your views here.
def reg(request:HttpRequest):
try:
# print(request.body)
payload = simplejson.loads(request.body)
email = payload['email']
user = User.objects.filter(email=email)
print(user.query)
print(user,type(user))
return HttpResponse(b'user')
except Exception as e:
print(e)
return HttpResponseBadRequest('erro')
数据跟数据库内的用户比对
from django.shortcuts import render
from django.http import HttpResponse,HttpRequest,HttpResponseBadRequest
import simplejson
from .models import User
# Create your views here.
def reg(request:HttpRequest):
try:
# print(request.body)
payload = simplejson.loads(request.body)
email = payload['email']
#查询数据库比对邮箱是否唯一
user = User.objects.filter(email=email)
# print(user.query)
# print(user,type(user))
if user:
return HttpResponseBadRequest()
#没有邮箱
name = payload['name']
password= payload['payload']
user = User()
user.name = name
user.email=email
user.password = password
user.save() #保存到数据库 django的model、save、update、delete会自动提交
return HttpResponse(b'user')
except Exception as e:
print(e)
return HttpResponseBadRequest('erro')
用户信息数据库加入成功
Django日志
配置
在官网文档查找logging 找到example复制到setting.py
模型操作
管理器对象
Django会给模型类提供一个objects对象,自己指定的话,django就不提供了
查询
def test(request:HttpRequest):
qs = User.objects.all()
print(type(qs))
print([x for x in qs])
print([x for x in qs])
print(qs)
print(qs)
return HttpResponse()
查询会返回结果的集,是<class ‘django.db.models.query.QuerySet’>类型
它是惰性求值,和sqlalchemy一样
惰性求值:创建查询集不会带来任何数据库的访问,直到调用使用数据才会访问数据库
缓存:每一个查询集都包含一个缓存,接下来的查询集求值将使用缓存的结果
限制查询集
all | 所以默认limit 21 |
---|---|
filter | 过滤 返回满足条件的 |
exiude | 排除 where not value |
order_by | 排序,参数是字符串(order_by(‘-pk’)负号逆序) |
values | 返回一个对象字典的列表(查询语句后加,一般用于观察数据) |
返回单个值得方法
get | 返回满足条件的对象,没有找到抛出notexist异常,找到多个抛出multipleobjectreturned异常 |
---|---|
count | 返回当前查询的总条数 |
first | 返回第一个对象 |
exist | 判断查询集中是否有数据,有返回T |
last | 返回最后一个对象 |
查询表达式
查询表达式作为前面查询方法的参数
语法:属性名称__比较运算符=值
属性名和运算符之间使用双下划线
startwith,endwith | 开头结尾 |
---|---|
isnull,isnotnull | 是否为null |
contains | 包含,大小写敏感 |
exact,lt,gt,lte,gte | 等于,小于,大于,小于等于,大于等于 |
前面所的前面加i | 忽略大小写 |
in | 在什么范围 |
year,month,day,week_day,hour,minute,second | 日期处理 |
Q对象
Q对象,可以使用& ,|操作符来组成逻辑表达式,~表示not
from django.db.models import Q
def test(request:HttpRequest):
qs = User.objects.filter(Q(id=1) |Q(id=2)).values()
# print(type(qs))
# print([x for x in qs])
# print([x for x in qs])
# print(qs)
# print(qs)
print(qs)
return HttpResponse()
如果要混合关键字查询和Q对象,Q对象必须在关键字前面
注册接口设计完善
认证
HTTP协议是无状态协议,为了解决产生了cookies和session技术
传统的session-cookies机制,就是访问浏览器好哦偶浏览器给你一个session id,session中可以创建很多东西,服务器端保存大量的session信息
无session方案
浏览器需要一个id来表示身份还要保证客户端不可篡改信息
服务器端生成一个标识,并使用某种算法对标识签名
这方案的缺点是加密,解密需要消耗cpu计算资源,无法让浏览器自己主动检查过期的数据以清除,这技术叫JWT(JSON WEB token)
import jwt
key = '123456'
payload = {'person':'hua'}
x = jwt.encode(payload,key,'HS256')
print(x)
header,payload,sig = x.split(b'.')
print(header)
print(payload)
print(sig)
import base64
def addequ(s):
rest = 4-len(s)%4
return s + b'='*rest
payload = addequ(payload)
print(payload)
print(base64.urlsafe_b64decode(header))
print(base64.urlsafe_b64decode(payload))
print(base64.urlsafe_b64decode(addequ(sig)))
JWT就是用一个key加上数据用算法加密 得到header,数据,sig
浏览器将token发给成功登录的客户端,客户端请求上带着token,浏览器在用key计算和签名对比,一样,浏览器就认可
查看源码我们知道了JWT的全部过程 下面我们自己来实现JWT的加密过程
加载包,得到算法
得到key
得到signing_input
得到signature
总结:jwt生成都token为三部分:header,数据,签名
数据交换:使用私钥,密钥加密
密码
加盐,使用hash(password+salt)的结果存入数据库。随机加盐,增加了破解的难度
import bcrypt
password = b'123456'
salt = bcrypt.gensalt()
x= bcrypt.hashpw(password,salt) #相同盐
y = bcrypt.hashpw(password,salt)
print(x,y,sep='\n')
x= bcrypt.hashpw(password,bcrypt.gensalt()) #不同盐
y = bcrypt.hashpw(password,bcrypt.gensalt())
print(x,y,sep='\n')
重写reg
def reg(request:HttpRequest):
try:
# print(request.body)
payload = simplejson.loads(request.body)
email = payload['email']
# print(email)
#查询数据库比对邮箱是否唯一
user = User.objects.filter(email=email)
# print(user.query)
# print(user,type(user))
if user:
return HttpResponseBadRequest()
#没有邮箱
name = payload['name']
password= payload['password']
password = bcrypt.hashpw(password.encode(),bcrypt.gensalt())
# print(name,email,password)
user = User()
user.name = name
user.email=email
user.password = password
user.save() #保存到数据库 django的model、save、update、delete会自动提交
return JsonResponse({'token':get_token(user.id)})
except Exception as e:
print(e)
return HttpResponseBadRequest('erro')
用户功能设计与实现
用户登录接口设计
def login(request:HttpRequest):
# qs = User.objects.filter(Q(id=1) |Q(id=2)).values()
# print(type(qs))
# print([x for x in qs])
# print([x for x in qs])
# print(qs)
# print(qs)
try:
payload = simplejson.loads(request.body)
password = payload['password'].encode()
email = payload['email']
user = User.objects.get(email=email)
#验证密码
if bcrypt.checkpw(password,user.password.encode()):
res = JsonResponse({
'user':{
'user_id':user.id,
'name':user.name,
'email':user.email,
},
'token':get_token(user.id)
})
res.set_cookie('jwt',get_token(user.id)) #token两种一个在json里 一个了可以setcookie 自己选方案
return res
else:
return HttpResponseBadRequest()
except Exception as e:
return HttpResponseBadRequest()
认证
如何获取浏览器的cookie信息?
1.使用header中的Authorization
2.自定义header:使用JWT字段发送token
class SimpleMiddleware(object):
def __init__(self,get_response):
self.get_response = get_response
def __call__(self,request):
#request拦截处理
#对header的jwt信息验证
#<class 'django.core.handlers.wsgi.WSGIRequest'>
print(type(request),'~~~~~~~~~')
response = self.get_response(request)
#response拦截处理
return response
使用前先注册
装饰器实现代码
def authenticate(viewfunc):
def wrapper(request:HttpRequest):
# auth = request.META.get('HTTP_JWT')
# if not auth:
# return HttpResponse(status=401)
# print((request.META['HTTP_JWT']))
try:
auth = request.META['HTTP_JWT']
print('!!!!!!!!')
payload= jwt.decode(auth,settings.SECRET_KEY, algorithms=[settings.ALG])
print(payload,'~~~~~~~~~')
user = User.objects.get(pk=payload['USER_ID'])
#timestamp
current = datetime.datetime.now().timestamp()
delta = current - payload['TIMESTAMP']
if delta> AUTH_EXPIRE or delta <= 0:
print('+++++++++++++')
return HttpResponse(status=401)
except:
return HttpResponse(status=401)
ret = viewfunc(request)
return ret
return wrapper
@authenticate #auth验证用户身份,不通过返回401
def test(request):
return HttpResponse(b'test ok')
jwt过期
jtw在payload中增加clamin exp。exp要求int整数的时间戳(到期时间)
import jwt
import datetime
import threading
key = '123456'
payload = {
'person':'hua',
'exp':int(datetime.datetime.now().timestamp()) +10
}
x = jwt.encode(payload,key,'HS256')
print(1,jwt.get_unverified_header(x))
event = threading.Event()
try:
while not event.wait(1):
print(datetime.datetime.now().timestamp())
jwt.decode(x,key,algorithms=['HS256'])
except Exception as e:
print(e)
print(2,jwt.get_unverified_header(x))