a. 有些API需要用户登录成功之后,才能访问;有些无需登录就能访问。
b. 基本使用认证组件 解决思路: a. 创建两张表(用户表,token表) b. 用户登录(返回token并保存到数据库)
c.涉及两种操作(全局认证,单独认证)
e. 使用框架内置认证类(自己写认证类的时候继承自BaseAuthentication这个类,更规范,不用自己从头搞)
认证类,必须继承:from rest_framework.authentication import BaseAuthentication 其他认证类:BasicAuthentication(可以浏览器自动生成非模态对话框的一种认证类,SessionAuthentication等等,这些都是基于BaseAuthentication浏览器帮助加密,放到请求头里边传过去得到,基本用不到) 3.大多场景下,继承自BaseAuthentication,然后自己定义认证类 基类如下: class BaseAuthentication(object): """ All authentication classes should extend BaseAuthentication. """ def authenticate(self, request): """ Authenticate the request and return a two-tuple of (user, token). """ raise NotImplementedError(".authenticate() must be overridden.") def authenticate_header(self, request): # 认证失败时,返回的响应头的定义 """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass创建类:继承BaseAuthentication; 实现:authenticate方法,其中authenticate_header方法,不用写,直接按基类pass就行
authenticate的返回值:
1.返回None,跳过,让下一认证来执行。2.返回(抛出)异常(这里上边类有队异常的接收跟处理)raise exceptions.AuthenticationFailed(用户认证失败 from rest_framework import exceptions)3.返回一个元组(元素1,元素2) # 元素1赋值给request.user; 元素2赋值给request.auth,可以在views.py视图中对返回的两个,进行调用,比如拿到验证通过的对象user(前提定义函数时,得返回user相关的信息)局部使用(局部针对某些类进行验证,针对单独的类添加静态字段)
from rest_framework.authentication import BaseAuthentication,BasicAuthentication class UserInfoView(APIView): """ 订单相关业务 """ authentication_classes = [BasicAuthentication,] # 设置这静态字段,单独设置 def get(self,request,*args,**kwargs): print(request.user) return HttpResponse('用户信息') 全局使用(在settings里边设置配置文件): 全局使用时的文件为路径字符串,如下;而在局部用时,直接添加验证类的名字就行。REST_FRAMEWORK = { # 全局使用的认证类
```python REST_FRAMEWORK = { # 全局使用的认证类 "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ], #里边写的类文件的位置 # "UNAUTHENTICATED_USER":lambda :"匿名用户" "UNAUTHENTICATED_USER":None, # 匿名,request.user = None "UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None }权限知识梳理: 同上,为了代码规范,最好也继承自BasePermission
类,必须继承:BasePermission,必须实现:has_permission方法,其中还有个has_object_persion方法,用来细化到针对对象的权限判断 from rest_framework.permissions import BasePermission class SVIPPermission(BasePermission): message = "必须是SVIP才能访问" def has_permission(self,request,view): if request.user.user_type != 3: return False return True 返回值: True, 有权访问False,无权访问 局部使用 class UserInfoView(APIView): """ 订单相关业务(普通用户、VIP) """ permission_classes = [MyPermission1, ] def get(self,request,*args,**kwargs): return HttpResponse('用户信息') 全局使用 REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES":['api.utils.permission.SVIPPermission'] }控制请求的访问频率,具体实现
代码实现是拿ip来记录,对于没登录的匿名用户,我们能拿到的也只有ip,要是换ip访问,这个控制不了
访问的ip地址的获得方式 : request.META.get('REMOTE_ADDR)
1.类, 若继承:BaseThrottle,要自己实现:allow_request、wait2.类, 若继承:SimpleRateThrottle,只需实现实现:get_cache_key、其中的一个字段:scope = “Luffy”(配置文件中限制节流频率的key) import time VISIT_RECORD = {} class VisitThrottle(object): """60s内只能访问3次""" def __init__(self): self.history = None def allow_request(self,request,view): # 1. 获取用户IP remote_addr = request.META.get('REMOTE_ADDR') ctime = time.time() if remote_addr not in VISIT_RECORD: VISIT_RECORD[remote_addr] = [ctime,] return True history = VISIT_RECORD.get(remote_addr) self.history = history while history and history[-1] < ctime - 60: history.pop() if len(history) < 3: history.insert(0,ctime) return True # return True # 表示可以继续访问 # return False # 表示访问频率太高,被限制 def wait(self): """ 还需要等多少秒才能访问 :return: """ ctime = time.time() return 60 - (ctime - self.history[-1]) class AuthView(APIView): """ 用于用户登录认证 """ authentication_classes = [] permission_classes = [] throttle_classes = [VisitThrottle,] def post(self,request,*args,**kwargs): ret = {'code':1000,'msg':None} try: user = request._request.POST.get('username') pwd = request._request.POST.get('password') obj = models.UserInfo.objects.filter(username=user,password=pwd).first() if not obj: ret['code'] = 1001 ret['msg'] = "用户名或密码错误" # 为登录用户创建token token = md5(user) # 存在就更新,不存在就创建 models.UserToken.objects.update_or_create(user=obj,defaults={'token':token}) ret['token'] = token except Exception as e: ret['code'] = 1002 ret['msg'] = '请求异常' return JsonResponse(ret)