logininfo总结:
- 框架其实就是 流程、套路;
1. Django的认证
django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
1、authenticate(**credentials)
提供了用户认证,即验证用户名以及密码是否正确
user = authentica(username='someone',password='somepassword')
2、login(HttpRequest, user, backend=None)
该函数接受一个HttpRequest对象,以及一个认证了的User对象
此函数使用django的session框架给某个已认证的用户附加上session id等信息。
3、logout(request) 本次使用
注销用户
该函数接受一个HttpRequest对象,无返回值。
当调用该函数时,当前请求的session信息会全部清除
该用户即使没有登录,使用该函数也不会报错
还提供了一个装饰器来判断是否登录django.contrib.auth.decorators.login_required
本项目使用了无session机制,且用户信息自己建表管理,所以,认证需要自己实现。
2. 中间件技术Middleware
官方定义,在Django的request和response处理过程中,由框架提供的hook钩子
中间件技术在1.10后发生了改变,我们当前使用1.11版本,可以使用新的方式定义。
参看 https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware
# 要在setting的MIDDLEWARE中注册;
class AuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
print(request,'++++++++++++++++++++++++++')
token = request.META.get('HTTP_JWT',None)
print(token)
# 统计IP验证 : 1分钟1000次以上; 使用字典记录次数 =》 redis kv; 调shell - 防火墙;
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
但是, 这样所有的请求和响应都拦截, 我们还得判断是不是访问的想要拦截的view函数, 所以, 考虑其他方法。
中间件有很多用途, 适合拦截所有请求和响应。例如 浏览器端的IP是否禁用、UserAgent分析、异常响应的统一处理。
3. 装饰器*
在需要认证的view函数上增强认证功能,写一个装饰器函数。谁需要认证,就在这个view函数上应用这个装饰器。
AUTH_EXPIRE = 8 * 60 * 60 # 8小时过期
def authenticate(view):
def wrapper(request: HttpRequest):
# 自定义header jwt
payload = request.META.get('HTTP_JWT') # 会被加前缀HTTP_且全大写
if not payload: # None没有拿到,认证失败
return HttpResponse(status=401)
try: # 解码
payload = jwt.decode(payload, settings.SECRET_KEY, algorithms=['HS256'])
print(payload)
except:
return HttpResponse(status=401)
# 验证过期时间
current = datetime.datetime.now().timestamp()
if (current - payload.get('timestamp', 0)) > AUTH_EXPIRE:
return HttpResponse(status=401)
print('-' * 30)
try:
user_id = payload.get('user_id', -1)
user = User.objects.filter(pk=user_id).get()
request.user = user # 如果正确,则注入user
print('-' * 30)
except Exception as e:
print(e)
return HttpResponse(status=401)
ret = view(request) # 调用视图函数
# 特别注意view调用的时候,里面也有返回异常
return ret
return wrapper
@authenticate # 很自由的应用在需要认证的view函数上
def test(request: HttpRequest):
return HttpResponse('test')
from django.http import JsonResponse,HttpRequest,HttpResponseBadRequest
import simplejson,jwt,bcrypt,datetime
from .models import User
from django.db.models import Q
from django.conf import settings
AUTH_EXPIRE = 8*60*60
def gen_token(user_id): # 生成令牌;
key = settings.SECRET_KEY
return jwt.encode({'user_id':user_id,
'timestamp':int(datetime.datetime.now().timestamp() + AUTH_EXPIRE) # 结束时间
},key,'HS256').decode()
# 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 JsonResponse({
'user_id':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 login(request:HttpRequest):
try:
payload = simplejson.loads(request.body)
email = payload['email']
password = payload['password']
user = User.objects.filter(email=email).first()
if user: # 登录成功,返回信息
if bcrypt.checkpw(password.encode(),user.password.encode()):
token = gen_token(user.id)
res = JsonResponse({
'user':{
'user_id': user.id,
'name': user.name,
'email': user.email
}, 'token': token
})
res.set_cookie('jwt',token) # 演示 如何 set_cookie
return res
else:
return HttpResponseBadRequest('登录失败3')
else:
return HttpResponseBadRequest('登录失败1')
except Exception as e: # 记录登录日志;
print(e)
return HttpResponseBadRequest('登录失败2')
# 谁认证就给谁加装饰器;
def auth(view_func):
def wrapper(request:HttpRequest):
token = request.META.get('HTTP_JWT', None) # 拿到http_jwt 字典的值
# print(list(filter(lambda x: x.lower().endswith('jwt'),meta))) #查询 http_jwt
print(token)
if not token: # 认证失败
return HttpResponseBadRequest()
key = settings.SECRET_KEY
try:
print('=============================')
payload = jwt.decode(token, key, algorithms=['HS256']) # 解失败,被改过;接成功;没改过;
# dt = payload['timestamp']
# current = datetime.datetime.now().timestamp()
#
# if (current - dy) > AUTH_EXPIRE: # exp check 过期检查;
# return HttpResponseBadRequest('expire')
# user_id = payload.get('user_id',-1)
user = User.objects.filter(pk=payload['user_id']).first() # 查询一次数据库;
# user = User.objects.filter(pk=payload['user_id']).filter(isactive=True).first()
if user: # 拿到user,
request.user = user #request 动态添加属性;
ret = view_func(request)
return ret
else:
return HttpResponseBadRequest('1用户名密码错误')
except jwt.ExpiredSignatureError as e:
print(e)
return HttpResponseBadRequest('jwt过期')
except Exception as e:
print(e)
return HttpResponseBadRequest('用户名密码错误')
return wrapper
@auth # 认证拦截
def show(request): # 方法的使用方式各不相同;
# print(request.user,'---------------------------')
return JsonResponse({'status':'ok'})
# 要在setting的MIDDLEWARE中注册;
class AuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
print(request,'++++++++++++++++++++++++++')
token = request.META.get('HTTP_JWT',None)
print(token)
# 统计IP验证 : 1分钟1000次以上; 使用字典记录次数 =》 redis kv; 调shell - 防火墙;
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
网友评论