---恢复内容开始---
1、用户功能设计与设计:
提供用户注册处理
提供用户登录处理
提供路由配置
2、用户登录接口设计:
接受用户通过POST 方法提交的登录信息,提交的数据是JSON 格式数据。
从user表中 email 找出匹配的一条记录, 验证密码是否正确
验证通过说明是合法的用户登录,显示欢迎页面
验证失败返回错误状态码,4XX
整个过程都采用AJAX异步过程,用户提交JSON 数据,服务端回去数据后处理,返回JSON
URL: /user/login
METHOD:POST
3、路由配置:
4、登录代码:
1 # 登录业务 2 def login(request:HttpRequest): 3 play = simplejson.loads(request.body) 4 try: 5 # 一般推荐先有索引的放前面 6 email = play['email'] 7 user = User.objects.filter(email=email).get() 8 9 # 输入密码 和 数据库中密码对比 10 if bcrypt.checkpw(play['password'].encode(), user.password.encode()): 11 # 验证通过 12 token = gen_token(user.id) 13 res = JsonResponse({ 14 'user':{ 15 "user_id":user.id, 16 "name":user.name, 17 "email":user.email 18 }, 19 'token':token 20 }) 21 res.set_cookie('Jwt', token) # set cookie 22 return res 23 else: 24 return HttpResponseBadRequest(status=400) 25 except Exception as e: 26 return JsonResponse("输入有误")
1、将用户信息返回去,浏览器可以使用,处了密码
2、服务器端通过set_cookie 让客户端强行修改cookie(客户端一般都开启的cookie)
5、接口认证:
如何获取浏览器提交的token信息?
1、使用Header中的Authorization
通过这个header增加token信息
通过header发送数据,方法可以是post , get
2、自定义header
JWT来发送token
我们选择第二种
认证:
基本上所有的业务都需要认证用户的信息
在这里比较时间戳,如果过期,就直接抛未认证401,客户端收到后就该直接跳转到登录页
如果没有提交user id,就直接重新登录,如果用户查到了,填充user对象。
request -》 时间戳比较-》 user id 比较 --》向后执行。
测试: 没有报错,就证明是没有修改过的
提供一个函数,调用业务函数之前,看下,之前是否登陆过
1 # 只要需要认证的地方都可以加这个功能,是否登陆过 2 def auth(view_func): 3 def wrapper(request:HttpRequest): 4 token = request.META.get('HTTP_JWT', None) 5 print(token,type(token),'== = = = = ') # str 6 try:# 获取到 token中的payload,证明是之前登录过的用户 7 play = jwt.decode(token, KEY, algorithms=['HS256']) 8 print(play, type(play),'=============') 9 # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等 10 user = User.objects.get(pk=play["user_id"]) 11 print(user,'==== = = = = = = == ') 12 # 如果查到了,接下来的业务处理: 13 if user: 14 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中 15 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了 16 # 如果没查到,user就报错了,所以这块没必要写 17 # else: 18 # return HttpResponseBadRequest() 19 except Exception as e: 20 print(e) 21 return HttpResponseBadRequest('n or p 错误') 22 ret = view_func(request) 23 # 这个中间还可以执行去其他的业务。。。。。 24 return ret 25 return wrapper 26 27 @auth -----装饰器实现 28 def show(request:HttpRequest): 29 # 例如: 30 print(request.user,'==') 31 print(type(request.user)) 32 return JsonResponse({'1':7})
---恢复内容结束---
1、用户功能设计与设计:
提供用户注册处理
提供用户登录处理
提供路由配置
2、用户登录接口设计:
接受用户通过POST 方法提交的登录信息,提交的数据是JSON 格式数据。
从user表中 email 找出匹配的一条记录, 验证密码是否正确
验证通过说明是合法的用户登录,显示欢迎页面
验证失败返回错误状态码,4XX
整个过程都采用AJAX异步过程,用户提交JSON 数据,服务端回去数据后处理,返回JSON
URL: /user/login
METHOD:POST
3、路由配置:
4、登录代码:
1 # 登录业务 2 def login(request:HttpRequest): 3 play = simplejson.loads(request.body) 4 try: 5 # 一般推荐先有索引的放前面 6 email = play['email'] 7 user = User.objects.filter(email=email).get() 8 9 # 输入密码 和 数据库中密码对比 10 if bcrypt.checkpw(play['password'].encode(), user.password.encode()): 11 # 验证通过 12 token = gen_token(user.id) 13 res = JsonResponse({ 14 'user':{ 15 "user_id":user.id, 16 "name":user.name, 17 "email":user.email 18 }, 19 'token':token 20 }) 21 res.set_cookie('Jwt', token) # set cookie 22 return res 23 else: 24 return HttpResponseBadRequest(status=400) 25 except Exception as e: 26 return JsonResponse("输入有误")
1、将用户信息返回去,浏览器可以使用,处了密码
2、服务器端通过set_cookie 让客户端强行修改cookie(客户端一般都开启的cookie)
5、接口认证:
如何获取浏览器提交的token信息?
1、使用Header中的Authorization
通过这个header增加token信息
通过header发送数据,方法可以是post , get
2、自定义header
JWT来发送token
我们选择第二种
认证:
基本上所有的业务都需要认证用户的信息
在这里比较时间戳,如果过期,就直接抛未认证401,客户端收到后就该直接跳转到登录页
如果没有提交user id,就直接重新登录,如果用户查到了,填充user对象。
request -》 时间戳比较-》 user id 比较 --》向后执行。
测试: 没有报错,就证明是没有修改过的
提供一个函数,调用业务函数之前,看下,之前是否登陆过
1 # 只要需要认证的地方都可以加这个功能,是否登陆过 2 def auth(view_func): 3 def wrapper(request:HttpRequest): 4 token = request.META.get('HTTP_JWT', None) 5 print(token,type(token),'== = = = = ') # str 6 try:# 获取到 token中的payload,证明是之前登录过的用户 7 play = jwt.decode(token, KEY, algorithms=['HS256']) 8 print(play, type(play),'=============') 9 # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等 10 user = User.objects.get(pk=play["user_id"]) 11 print(user,'==== = = = = = = == ') 12 # 如果查到了,接下来的业务处理: 13 if user: 14 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中 15 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了 16 # 如果没查到,user就报错了,所以这块没必要写 17 # else: 18 # return HttpResponseBadRequest() 19 except Exception as e: 20 print(e) 21 return HttpResponseBadRequest('n or p 错误') 22 ret = view_func(request) 23 # 这个中间还可以执行去其他的业务。。。。。 24 return ret 25 return wrapper 26 27 @auth -----装饰器实现 28 def show(request:HttpRequest): 29 # 例如: 30 print(request.user,'==') 31 print(type(request.user)) 32 return JsonResponse({'1':7})
Django的认证:
本项目使用了无session的机制,且用户信息自己建表管理,所以认证需要自己实现
6、中间件技术Midleware
官方定义:在Django的request 和response处理过程中,由框架提供的hook钩子
中间件技术,在1.10之后,发生改变,使用新的定义方式
参看:https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware
中间件实现方式:有两种
自定义的中间件,也要在这里注册:一般写在最后,先用框架自己的中间件。
自己写中间件:https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware
右击中间件名,选择copyreference,添加到settings.py中。
但是,这样所有的请求和响应都拦截,我们还得判断是不是访问的想要拦截的view函数,所以,考虑其他的方法。中间件有很多用途,适当的拦截所有请求和响应,例如浏览器端的IP 是否被禁用,UserAgent分析,异常响应的统一处理。
例如本项目的认证,登录的时候,就不能用中间件,所以不适合注册一个中间件来拦截,而是使用装饰器,需要拦截的就加上此功能。
装饰器:
在需要认证 的view 函数上增加认证功能,写一个装饰器函数,谁需要认证,就在这个view函数上应用这个装饰器
1 AUTH_EXPIRE = 8*60*60 # 8 小时过期,可以卸载settings中,通过from django.conf import settings调用 2 # 只要需要认证的地方都可以加这个功能,是否登陆过 3 def auth(view_func): 4 def wrapper(request:HttpRequest): 5 token = request.META.get('HTTP_JWT', None) 6 print(token,type(token),'== = = = = ') # str 7 try:# 获取到 token中的payload,证明是之前登录过的用户 8 play = jwt.decode(token, KEY, algorithms=['HS256']) 9 # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等 10 # 验证过期时间: 11 current = datetime.datetime.now().timestamp() 12 if (current - play.get('timestamp', 0)) > AUTH_EXPIRE: 13 return HttpResponse("过期了") 14 15 user = User.objects.get(pk=play["user_id"]) 16 # 如果查到了,接下来的业务处理: 17 if user: 18 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中 19 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了 20 # 如果没查到,user就报错了,所以这块没必要写 21 # else: 22 # return HttpResponseBadRequest() 23 except Exception as e: 24 print(e) 25 return HttpResponseBadRequest('n or p 错误') 26 ret = view_func(request) 27 # 这个中间还可以执行去其他的业务。。。。。 28 return ret 29 return wrapper 30 31 @auth # 很自由的应用在需要认证的view 函数上。 32 def show(request:HttpRequest): 33 # 例如: 34 print(request.user,'==') 35 print(type(request.user)) 36 return JsonResponse({'1':7})
Jwt 过期问题:(过期两种方式:过期的起点时间 和 到期时间)
pyjwt 支持过期设定,在decode的时候,如果过期,则抛出异常,
需要在payload中增加 claim exp。exp要求是一个整数int的时间戳。
1 # 只要需要认证的地方都可以加这个功能,是否登陆过 2 def auth(view_func): 3 def wrapper(request:HttpRequest): 4 token = request.META.get('HTTP_JWT', None) 5 print(token,type(token),'== = = = = ') # str 6 try:# 获取到 token中的payload,证明是之前登录过的用户 7 # 认证的同时,验证过期时间:过期或抛异常(可以通过时间判断,块过期的时候,续期,set cookie重新发一次) 8 play = jwt.decode(token, KEY, algorithms=['HS256']) 9 # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等 10 11 user = User.objects.get(pk=play["user_id"]) 12 # 如果查到了,接下来的业务处理: 13 if user: 14 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中 15 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了 16 # 如果没查到,user就报错了,所以这块没必要写 17 # else: 18 # return HttpResponseBadRequest() 19 except Exception as e: 20 print(e) 21 return HttpResponseBadRequest('n or p 错误') 22 ret = view_func(request) 23 # 这个中间还可以执行去其他的业务。。。。。 24 return ret 25 return wrapper
测试用的:exp claim,此代码,可以用于续期,通过判断,快过期,就通过set cookie重新发一个jwt 过去。
1 import jwt 2 import datetime 3 import threading 4 5 event = threading.Event() 6 key = 'jerry' 7 # 在jwt 的payload中增加 exp claim 8 data = jwt.encode({'name':'jerry','exp':int(datetime.datetime.now().timestamp() + 3)}, key) 9 print(jwt.get_unverified_header(data))# 获取没有过期的头 10 try: 11 while not event.wait(1): 12 print(jwt.decode(data, key)) 13 print(datetime.datetime.now().timestamp()) 14 except jwt.ExpiredSignatureError as e:# 过期就抛异常 15 print(e) 16 17 print(jwt.get_unverified_header(data))