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('您没有登录')

posted @ 2022-10-08 20:41  瓮小辉  阅读(39)  评论(0)    收藏  举报