本文目录:
一、drf认证功能
1.认证简介:
只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录则不能查看。这时候需要用到认证组件
2.局部使用
models层
class User(models.Model): name = models.CharField(max_length=32) password = models.CharField(max_length=32) class UserToken(models.Model): token = models.CharField(max_length=64) user = models.OneToOneField(to='User')
新建认证类(验证通过return两个参数)
from rest_framework.authentication import BaseAuthentication class Authlogin(BaseAuthentication): def authenticate(self, request): token = request.GET.get('token') res = models.UserToken.objects.filter(token=token).first() if res: # 说明这个人登录了 # return None return res.user, token else: # 说明没有登录 raise NotAuthenticated("您没有登录")
views层
def get_token(name): m = hashlib.md5(name.encode("utf-8")) print(m.hexdigest()) res = m.hexdigest() return res class Login(APIView): #authentication_classes = [] def post(self, request): response = {'status': 100, 'msg': None} # 把用户名和密码取到 name = request.data.get('name') pwd = request.data.get('password') print(name, pwd) # 取出数据库的用户数据 user = models.User.objects.filter(name=name, password=pwd).first() print(user) if user: response['msg'] = '登录成功!' # 随机字符串可以是用户名+当前同时生成md5 # uuid token = get_token(name) # user = user 查询条件 defaults={'token':token} models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) response['token'] = token else: # response['status']后面是等于号不是冒号 response['status'] = 101 print(response['status']) response['msg'] = '用户名或密码错误' return Response(response)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def get_token(id,salt='123'): import hashlib md=hashlib.md5() md.update(bytes(str(id),encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) return md.hexdigest()+'|'+str(id) def check_token(token,salt='123'): ll=token.split('|') import hashlib md=hashlib.md5() md.update(bytes(ll[-1],encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) if ll[0]==md.hexdigest(): return True else: return False class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') success=check_token(token) if success: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass class Login(APIView): def post(self,reuquest): back_msg={'status':1001,'msg':None} try: name=reuquest.data.get('name') pwd=reuquest.data.get('pwd') user=models.User.objects.filter(username=name,password=pwd).first() if user: token=get_token(user.pk) # models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) back_msg['status']='1000' back_msg['msg']='登录成功' back_msg['token']=token else: back_msg['msg'] = '用户名或密码错误' except Exception as e: back_msg['msg']=str(e) return Response(back_msg) from rest_framework.authentication import BaseAuthentication class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if token_obj: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass class Course(APIView): authentication_classes = [TokenAuth, ] def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
-把{name:lqz,id:1} 用我自己知道的加密方式加密之后变成了:asdfasdf
-asdfasdf|{name:lqz,id:1} 当做token,发到客户端
-以后客户端再发请求,会携带asdfasdf|{name:lqz,id:1}过来
-服务端截取{name:lqz,id:1},再用我的加密方式加密:asdfasdf
-拿到加密后的串:asdfasdf和请求的asdfasdf比较,如果一样
bsdfasdf|{name:lqz,id:1}
-token好处是:服务端不需要存session了
总结:局部使用,只需要在试图类里加入
authentication_classes = [TokenAuth, ]
3.全局使用
*一般会将继承BaseAuthentication的token类抽出来单独放在一个auth.py文件中
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import NotAuthenticated from app import models class Authlogin(BaseAuthentication): def authenticate(self, request): token = request.GET.get('token') res = models.UserToken.objects.filter(token=token).first() if res: # 说明这个人登录了 # return None return res.user, token else: # 说明没有登录 raise NotAuthenticated("您没有登录")
*在setting文件中配置全局认证属性
# ["app.auth.Authlogin", ]中的Authlogin要与auth.py文件中视图类大小写一致
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["app.auth.Authlogin", ]
}
* 需要在login中加入局部禁用
authentication_classes = []
二、token讲解
-认证功能:
1 写一个类,继承BaseAuthentication
2 def authenticate(self,request) ,记住传request对象
-如果验证通过,返回None或者两个值
3 在视图类中使用:(不要加括号)
authentication_classes=[AuthLogin]
-认证功能的局部配置
-authentication_classes=[AuthLogin]
-认证功能的全局配置,在settings.py中配置
-REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.AuthLogin",]
}
-全局使用的局部禁用:
authentication_classes = []
-drf内置了一些认证类(了解):
-TokenAuthentication
-SessionAuthentication
#BaseAuthentication(规范了接口,模拟其它语言接口的概念) def authenticate(self, request): raise NotImplementedError(".authenticate() must be overridden.") # 如果写了一个类,继承BaseAuthentication,但是没有重写authenticate,就会抛异常
三、局部钩子源码分析
# 通过is_valid的父级查找到serializers
# 找到该文件下的to_internal_value方法
# 走完后走run_validation功能