drf-认证权限频率
drf-认证权限频率
-
认证Authentication
- 编写models
-
新建认证类
- 编写视图
-
编写路由
-
认证类完成的步骤
-
权限Permissions
-
限流Throttling
认证Authentication
编写models
1.编写用户表
class User(models.Model):
username = models.CharField(max_lengh = 32)
password = models.CharField(max_length=32)
def __str__(self):
return self.username
2.编写用户登录记录表
class UserToken(models.Model):
user = models.OneToOneField(to='User', on_delete=models.CASCADE)
token = models.CharField(max_length=32, null=True)
# 用户如果没有登录,就是空,如果登录了,就有值,登录多次以最后一次为准
新建认证类
from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 在这里做认证,校验用户是否登录(带了token,并且能查到,就是登录,返回两个值,否则就是没登录,抛异常)
# 用户带的token从哪取?后端人员定的:放在请求地址中
token = request.GET.get('token')
# 通过token查询该token是否是在表中有记录
user_token = UserToken.objects.filter(token=token).first()
if user_token:
return user_token.user, token # 返回两个值,一个是当前登录用户,一个是token
else:
raise AuthenticationFailed('您没有登录')
编写视图
class UserView(ViewSet):
authentication_classes = []
@action(methods=['POST', ], detail=False, url_path='login')
def login(self, request):
# 取出前端传入的用户名密码,校验,通过,返回登录成功,失败就返回用户名密码错误
username = request.data.get('username')
password = request.data.get('password')
user = User.objects.filter(username=username, password=password).first()
if user:
# 登录成功,不同人生成的token是不一样的,谁登录的,就把token存到UserToken表中
token = str(uuid.uuid4()) # 生成一个永不重复的随机字符串
# 存UserToken:如果没有记录,就是新增,如果有记录更新一下即可
# 通过user去UserToken表中查数据,如果能查到,使用defaults的数据更新,如果查不到,直接通过user和defaults的数据新增
UserToken.objects.update_or_create(defaults={'token': token}, user=user)
return Response({'code': 100, 'msg': '登录成功', 'token': token})
else:
return Response({'code': 101, 'msg': '用户名或密码错误'})
-
uuid的作用
生成一个永不重复的随机字符串,多用于认证
路由层
from rest_framework.routers import SimpleRouter, DefaultRouter
router = SimpleRouter()
router.register('user',views.UserView,'user')
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(router.urls)),
]
认证类
-
认证类的步骤
①写一个认证类,继承BaseAuthentication
②重写authenticate方法,在内部做认证
③如果认证通过,返回2个值(用户名和 用户认证后的随机字符串)
④认证不通过抛AuthenticationFailed异常
⑤ 只要返回了两个值,在后续的request.user 就是当前登录用户
⑥让某个视图类登录后才能访问
-
让某个视图类登录后才能访问有两种方式
方式一:
class BookView(ModelViewSet): authentication_classes = [LoginAuth,]
方式二:
-
全局配置(settings中)
REST_FRAMEWORK={ 'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.LoginAuth',] }
-
局部禁用
authentication_classes = []
先走自身的authentication_classes
-
⑦认证失败会有两种可能的返回值:
1.401——> Unauthorized 未认证
2.403——> Permission Denied 权限被禁止
-
内置的认证类
内置的认证中的类
-
BasicAuthentication
BasicAuthentication 是 基本认证
-
RemoteUserAuthentication
RemoteUserAuthentication 是 跟用户登录相关的
-
SessionAuthentication
SessionAuthentication是session认证
-
详情
1.如果前端带着cookie过来,经过session的中间件,如果登录了,在request.user中就有当前登录用户
2.drf没有限制是否登录
3.加了这个认证,如果没有登录,就不允许往后访问了
-
-
TokenAuthentication
TokenAuthentication认证是 jwt认证
权限Permissions
权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。
权限使用的步骤
①写一个类,继承BasePermission
②重写has_permission方法
③在方法中校验用户是否有权限(request.user就是当前登录用户)
④如果有权限,返回True,没有权限,返回False
⑤self.message 是给前端的提示信息
⑥通过权限判定查看用户是否有权限查看该视图
- 有两种方式
-
局部使用
# 局部使用只需要在视图类里加入: permission_classes = [UserTypePermission,]
-
全局使用,局部禁用
settings: REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.UserTypePermission",] } view: 在视图函数中加入 permission_classes = [ ]
-
编写权限类
from rest_framework.permissions import BasePermission
class UserTypePermission(BasePermission):
def has_permission(self, request, view):
# 只有超级管理员有权限
if request.user.user_type == 1:
return True # 有权限
else:
# self.message = '普通用户和2b用户都没有权限' # 返回给前端的提示是什么样
# 使用了choice后,user.user_type 拿到的是数字类型,想变成字符串 user.get_user_type_display()
# self.message = '您是:%s 用户,您没有权限'%request.user.get_user_type_display()
return False # 没有权限
内置的权限类
内置的认证中的类
-
BasePermission
所有的基类
-
AllowAny
允许所有通过权限
-
IsAuthenticated
判断是否登录,只有登录后才有权限进入
认证类,如果登录了,返回(当前登录用户,None), 如果没有登录返回 None
-
IsAdminUser
判断用户是否是超级管理员即auth的user表中is_staff字段是否为True
is_staff字段是指对后台管理有没有权限
限流Throttling
可以对接口访问的频次进行限制,以减轻服务器压力。
通常是利用用户的id或者 IP地址来进行限流
频率类的使用步骤
①写一个类:继承SimpleRateThrottle
②重写get_cache_key,返回唯一的字符串,会以这个字符串做频率限制
③写一个类属性scop='随意写',必须要跟配置文件对象
④配置文件 settings 中写配置文件
'DEFAULT_THROTTLE_RATES': {
'随意写': '3/m' # 3/h 3/s 3/d
}
⑤通过频率类的判定,管理用户是否能继续查看
-
有两种方式
-
局部配置
#在视图类里使用 throttle_classes = [MyThrottles,]
-
全局配置,局部禁用
settings: REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES':['app01.utils.MyThrottles',], 'DEFAULT_THROTTLE_RATES': { 'luffy': '3/m' } } view: throttle_classes = [ ]
-
频率类编写
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
class MyThrottling(SimpleRateThrottle): # 我们继承SimpleRateThrottle去写,而不是继承BaseThrottle去写
# 类属性,这个类属性可以随意命名,但要跟配置文件对应
scope = 'luffy'
def get_cache_key(self, request, view):
# 返回什么,频率就以什么做限制
# 可以通过用户id限制
# 可以通过ip地址限制
return request.META.get('REMOTE_ADDR')
内置的频率类
内置的频率的类
-
BaseThrottle
指所有的基类
-
SimpleRateThrottle
所写的频率类全继承这个类,少写了代码
-
AnonRateThrottle
按ip地址限制
在配置文件中配置
'DEFAULT_THROTTLE_RATES': { 'anon': '3/m', }
-
UserRateThrottle
按用户id限制
在配置文件中配置
'DEFAULT_THROTTLE_RATES': { 'user': '3/m', }
自定义频率类
from rest_framework.throttling import BaseThrottle
class MyThrottle(BaseThrottle):
VISIT_RECORD = {} # 存放用户访问记录{ip1:[时间1,时间2],ip2:[时间1,时间2],'192.168.1.101':[当前时间,]}
def __init__(self):
self.history = None
def allow_request(self, request, view):
# 在这里写逻辑:根据ip地址判断用户是不是超过了频率限制
# (1)取出访问者ip
ip = request.META.get('REMOTE_ADDR')
import time
ctime = time.time() # 取出当前时间
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
if ip not in self.VISIT_RECORD:
self.VISIT_RECORD[ip] = [ctime, ]
return True
self.history = self.VISIT_RECORD.get(ip) # 当前访问者的时间列表 [时间2,]
# (3)循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
while self.history and -ctime + self.history[-1] < 60: #循环结束后,剩下的都是1分钟以后访问的时间
self.history.pop()
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
if len(self.history) < 3:
self.history.insert(0, ctime)
return True
else:
return False
def wait(self):
import time
ctime = time.time()
return 60 - (ctime - self.history[-1])
其他
1) AnonRateThrottle
限制所有匿名未认证用户,使用IP区分用户。
使用DEFAULT_THROTTLE_RATES['anon']
来设置频次
2)UserRateThrottle
限制认证用户,使用User id 来区分。
使用DEFAULT_THROTTLE_RATES['user']
来设置频次
3)ScopedRateThrottle
限制用户对于每个视图的访问频次,使用ip或user id。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了