drf 路由及认证
1. 路由
-
自动生成路由
SimpleRouter使用
# urls.py from django.contrib import admin from django.urls import path, include from app01 import views # 导入 from rest_framework.routers import SimpleRouter # 实例化 router = SimpleRouter() # 注册 router.register('user', views.UserView, 'user') # 加入到urlpatterns中 urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls)),] # 1.导入 from rest_framework.routers import SimpleRouter, DefaultRouter # SimpleRouter与DefaultRouter的区别 DefaultRouter比SimpleRouter多一个根路径,显示所有注册过的路由 # 2.实例化: 实例化产生一个SimpleRouter的对象 router = SimpleRouter() # 3.注册 通过对象点方法register注册 def register(self,prefix, viewset, basename=None) pass register需要传入三个参数 第一个参数:路径 第二个参数:视图类 第三个参数:给视图类起别名 router.register('user', views.UserView, 'user') # 4. 加入urlpatterns中 4.1 使用urlpatterns+=router.urls 4.2 使用include path('', include(router.urls)) """ 自动生成的路由映射关系其实定死了 以后写的视图类不需要写action装饰器的化,视图类中必须要有 list,destroy,retrieve,create,update方法之一 其实是必须是 5个视图扩展类之一+GenericAPIView 9个视图子类,ModelViewSet """
-
action装饰器的使用
# views.py class UserView(ViewSet): @action(methods=['GET', 'POST'], detail=False, url_path='login', url_name='login') def login(self, request, pk): return Response('123') # 在视图函数中,会有一些其它名字的方法,必须要使用action装饰器做映射 def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs): pass methods:支持的请求方式,列表 detail:默认是False 控制生成的路由是 /user/login/ 还是 /user/pk/login 是不是带pk url_path:控制生成的/user/后的路径是什么,如果不写默认以方法名命名,一般以方法名命名即可 url_name:别名,用于反向解析 class UserView(ViewSet): @action(methods=['GET', 'POST'], detail=False, url_path='login', url_name='login') def login(self, request): return Response('123') # 这样写好以后,会自动生成路由,根据user/login/来进行匹配
2. 登录接口编写
#### 2.1 models.py
# 用户表
class User(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=32)
# 与用户表关联的token表,用于记录每个用户是否登录
class UserToken(models.Model):
# 用户如果没有登录就是空,如果登录就有值,多次登录以最后一次为准
token = models.CharField(max_length=32, null=True)
# 与用户表做关联
user = models.OneToOneField(to='User', on_delete=models.CASCADE)
2.2 view.py
from uuid import uuid4
from app01.models import User, UserToken
from rest_framework.decorators import action
from rest_framework.viewsets import ViewSet, ModelViewSet
class UserView(ViewSet):
@action(methods=['GET', 'POST'], detail=False, url_path='login', url_name='login')
def login(self, request):
# 取出前端传来的数据
name = request.data.get('name')
password = request.data.get('password')
user_obj = User.objects.filter(name=name, password=password).first()
# user_obj有,则表示校验通过
if user_obj:
# 校验通过说明登录成功,则通过uuid4()方法随机生成一个随机字符串
token = uuid4()
# 存UserToken:如果没有记录,就是新增,如果有记录更新一下即可
# 通过user去UserToken表中查数据,如果能查到,使用defaults的数据更新,如果查不到,直接通过user和defaults的数据新增
UserToken.objects.update_or_create(defaults={'token': token}, user=user_obj)
# 返回登录成功信息,并将用于识别记录用户是否登录的随机字符串也返回给前端
return Response({'code': 100, 'msg': '登录成功', 'token': token})
# user_obj有说明校验失败
else:
# 失败则返回登录失败信息
return Response({'code': 101, 'mag': '用户名或密码错误'})
2.3 urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from app01 import views
router = SimpleRouter()
router.register('user', views.UserView, 'user')
urlpatterns = [
path('admin/', admin.site.urls),
# 方式1
path('', include(router.urls)),
]
3.认证
# 访问接口,必须登录后才能访问
# 通过认证类完成
1. 写一个认证类,继承BaseAuthentication
2. 重写authenticate方法,在内部做认证
3. 如果认证通过,返回2个值
4. 认证不通过抛AuthenticationFailed异常
5. 只要返回了俩个值,后续的request.user就是当前登录用户
6. 控制视图函数登录后才能访问
6.1 局部配置,只针对配置了的当前视图类
class BookView(ModelViewSet):
authentication_classes = [认证类名,]
6.2 全局配置,针对所有视图类
在settings.py中添加配置
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES':['app01.auth.认证类名',]
}
6.3 局部禁用
authentication_classes = []
3.1 认证类
from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
# 写一个认证类,继承BaseAuthentication
class LoginAuth(BaseAuthentication):
# 重写authenticate方法,在内部做认证
def authenticate(self,request):
# 用户带的token从哪取?后端人员定的:放在请求地址中,取出token
token = request.GET.get('token')
# 通过token查询token是否在表中记录
token_obj = UserToken.objects.filter(token=token).first()
# 判断token_obj是否存在
if token_obj:
# 如果存在表示用户登录过,返回俩个值,一个是当前登录用户,一个是token
return token_obj.user,token
# 如果不通过抛异常
else:
raise AuthenticationFailed('您没有登录')