今日内容概要
- 路由组件
- 登录接口编写
- 三大认证之认证
- 三大认证之权限
- 三大认证之频率
路由组件
1.概念
只要继承了ViewSetMixin及其子类的视图类
2.自动生成路由
- 自动生成路由的写法:
(1)导入:from rest_framework.routers import StimpleRouter,DefaultRouter
(2)实例化:router= SimpleRouter()
(3)注册:router.register(‘user’,views.UserView,‘user’)
user:该视图集的路由前缀
view.UserView:视图集
user:路由别名的前缀
(4)加入到urlpatterns中
方式一:urlpatterns+=router.urls
方式二:path(‘’,include(router.urls))
3.自动生成的路由映射关系其实最初就已经固定不变的
- 举个栗子:
/books/------>get-------->list
/books/------>post------->create
/books/1------>get--------->retrieve
4.在视图类不写action装饰器的情况下,视图类中必须要有一下两点:
- list,destroy,retrieve,create,update方法之一;
- 必须是drf五个视图扩展类之一+GenericAPIView或9个视图子类,ModelViewSet
5.SimpleRouter和DefaultRouter对比
DefaultRouter比SimpleRouter多一个根路径,显示所有注册过的路由。
6.代码展示
- 使用路由类给视图集生成了路由地址
# 必须是继承ModelViewSet的视图类才能自动生成路由 from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer # 这种方法不会自动生成,需要用action配置 def login(self,request): "学生登录功能" print(self.action) return Response({"msg":"登录成功"})
- 路由代码:
from django.urls import path,re_path from .import views urlpatterns = [ ...] "使用drf提供路由类router给视图集生成路由列表" # 导入 from rest_framework.routers import DefaultRouter # 实例化路由类 router = DefaultRouter() # 注册视图集 router.register("路有前缀",视图集类) router.register("router_stu",views.StudentModelViewSet) # 把生成的路由列表追加到urlpatterns urlpatterns += router.urls
上面的代码成功生成了路由地址(增,删,改,查一条,查多条的功能),但是不会自动生成我们在视图集自定义方法的路由。
引出下面的action装饰器。
7.action装饰器的使用
@action(methods=['GET','POST'],detail=True,url_path='login') def login(self,request,pk)
- 在视图函数中,会有一些其他名字的方法,必须使用action装饰器做映射
(1)methods:支持的请求方式,列表
(2)detail:默认都是False,控制生成的路由是/user/login还是/user/pk/login
两者区别是是否带pk
(3)url_path:控制生成的/user/后的路径是什么,如果不写,默认以方法命名
/user/login/,一般跟函数名同名即可
(4)url_name:别名,用于反向解析
登录接口编写
1…models.py
# 用户表 class User(mosels.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) def __str__(self): return self.username # 用户登录记录表 # 如何区分用户是否登录了? class UserToken(models.Model): # SET_NULL SET_DEFAULT CASCADE SET(函数内存地址) user = models.OneToOneField(to='User', on_delete=models.CASCADE) token = models.CharField(max_length=32, null=True) # 用户如果没有登录,就是空,如果登录了,就有值,登录多次以最后一次为准
2.views.py
class UserView(ViewSet): authentication_class = [] @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':'用户名或密码错误'})
3.urls.py
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)), ]
三大认证之认证
访问接口,必须登录后才能访问
1. 通过认证类完成,使用步骤:
(1)写一个认证类,继承BaseAuthentication;
(2)重写authenicate方法,在内部做认证;
(3)如果认证通过,返回2个值;
(4)认证不通过抛AuthenticationFailed异常;
(5)只要返回了两个值,在后续的request.user就是当前登录用户;
(6)如果想让某个视图类登录后才能访问方式一: class BookView(ModelViewSet): authentication_classes = [LoginAuth,]
方式二:全局配置(settings.py中配置) REST_FRAMEWORK={ 'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.LoginAuth',]}
(7)局部禁用:
authentication_classes = []
2.认证类
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('您没有登录')
三大认证之权限
1.概念
- 认证:校验用户是否登录,登录认证;
- 用户登录了,某个接口可能只有超级管理员才能访问,,普通用户不能访问;
- 出版社的所有接口,必须登录,而且是超级管理员才能访问;
2.使用步骤
- 第一步:写一个类,继承BasePermission;
- 第二步:重写has_permission方法;
- 第三步:再方法中校验用户是否有权限(request.user就是当前登录用户);
- 第四步:如果有权限,返回True,没有权限,返回False;
- 第五步:self.message是给前端的提示信息;
- 第六步:局部使用,全局使用,局部禁用。
全局使用: REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",] } 局部使用: # 局部使用只需要在视图类里加入: permission_classes = [UserPermission,]
3.权限类
from rest_framwork.permissions import BasePermission class UserTypePermisssion(BasePermission): def has_permission(self,request,view): # 只有超级管理员有权限 if request.user.user_type == 1: return True # 有权限 else: # self,message = '普通用户和某些用户都没有权限' # 返回给前端的提示是什么样的 # 使用了choice后,user.user_type 拿到的是数字类型,想变成字符串user.get_user_type_display() # self.message = '您是:%s 用户,您没有权限' % request.user.get_user_type_display() return False # 没有权限
三大认证之频率
1.概念
无论是否登录和是否有权限,都要限制访问的频率,比如一分钟访问3次
2.使用步骤
- 第一步:写一个类:继承SimpleRateThrottle;
- 第二步:重写get_cache_key,返回唯一的字符串,会以这个字符串作为频率限制;
- 第三步:写一个类属性scop=‘随意些’,必须要跟配置文件对象;
- 第四步:配置文件中写:
'DEFAULT_THROTTLE_RATES':{ '随意写':'3/m' # 3/h 3/s 3/d }
- 第五步:局部配置,全局配置,局部禁用。
全局使用: REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES':['app01.utils.MyThrottles',], } 局部使用: #在视图类里使用 throttle_classes = [MyThrottles,]
3.频率类
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')
settings.py文件
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES':['app01.throttling.MyThrottling'], 'DEFAULT_THROTTLE_RATES': { 'luffy': '3/m' } }