版本控制和认证组件的使用

DRF版本组件

版本控制组件的作用

我们做一个项目,一般情况下会有迭代多个版本

随着我们项目的更新,我们自然会推送新的版本,但不会因此丢弃旧的版本,还是会维护旧的版本

那我们就需要对版本进行控制,这个DRF也给我们提供了一些封装好的版本控制方法

版本控制组件的使用

既然牵扯到版本信息,那必然会在请求过程中携带相关的版本信息,后端通过携带的版本信息返回对应的版本内容

因为我们用的是restframework,所以我们去看看drf在初始化request过程中做了什么事情吧

这里我直接从dispatch里找到initial方法跟进来,看到drf怎么封装的version

我们可以自己写相关的版本控制类,也可以用drf提供给我们的版本控制类(from rest_framework import versioning)

// drf提供给我们的版本控制类,如果想自己实现版本控制类,一定要重写determine_version方法
// BaseVersioning里提供了三个参数,也都可以自己定义

class BaseVersioning:
    default_version = api_settings.DEFAULT_VERSION
    allowed_versions = api_settings.ALLOWED_VERSIONS
    version_param = api_settings.VERSION_PARAM

    def determine_version(self, request, *args, **kwargs):
        msg = '{cls}.determine_version() must be implemented.'
        raise NotImplementedError(msg.format(
            cls=self.__class__.__name__
        ))

    def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
        return _reverse(viewname, args, kwargs, request, format, **extra)

    def is_allowed_version(self, version):
        if not self.allowed_versions:
            return True
        return ((version is not None and version == self.default_version) or
                (version in self.allowed_versions))


class AcceptHeaderVersioning(BaseVersioning):
    """
    GET /something/ HTTP/1.1
    Host: example.com
    Accept: application/json; version=1.0
    """
    .......


class URLPathVersioning(BaseVersioning):
    """
    To the client this is the same style as `NamespaceVersioning`.
    The difference is in the backend - this implementation uses
    Django's URL keyword arguments to determine the version.

    An example URL conf for two views that accept two different versions.

    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
        url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
    ]

    GET /1.0/something/ HTTP/1.1
    Host: example.com
    Accept: application/json
    """
    .......


class NamespaceVersioning(BaseVersioning):
    """
    To the client this is the same style as `URLPathVersioning`.
    The difference is in the backend - this implementation uses
    Django's URL namespaces to determine the version.

    An example URL conf that is namespaced into two separate versions

    # users/urls.py
    urlpatterns = [
        url(r'^/users/$', users_list, name='users-list'),
        url(r'^/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
    ]

    # urls.py
    urlpatterns = [
        url(r'^v1/', include('users.urls', namespace='v1')),
        url(r'^v2/', include('users.urls', namespace='v2'))
    ]

    GET /1.0/something/ HTTP/1.1
    Host: example.com
    Accept: application/json
    """
    .......

class HostNameVersioning(BaseVersioning):
    """
    GET /something/ HTTP/1.1
    Host: v1.example.com
    Accept: application/json
    """
    .......


class QueryParameterVersioning(BaseVersioning):
    """
    GET /something/?version=0.1 HTTP/1.1
    Host: example.com
    Accept: application/json
    """
    ........

我这里就挑一个做演示,其他类大致配置都相同,大家可根据自己的需求,举一反三

详细用法

我这里演示URLPathVersioning,个人看到的大多数网站都是把版本信息放在路径里的

  • settings/views

    # 如果是全局配置的话 则在settings里配置如下信息
    REST_FRAMEWORK = {
        # 默认使用的版本控制类
        'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
        # 允许的版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],
        # 版本使用的参数名称
        'VERSION_PARAM': 'version',
        # 默认使用的版本
        'DEFAULT_VERSION': 'v1',
    }
    # 如果只是对某一个视图类进行版本控制,则在视图类配置相关信息
    
    //views
    class TestView(APIView):
        versioning_class = URLPathVersioning
    
  • urls

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^(?P<version>.*?)/test/', views.TestView.as_view()),
    ]
    
  • views

    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            print(request.versioning_scheme)
            ret = request.version
            if ret == "v1":
                return Response("版本v1的信息")
            elif ret == "v2":
                return Response("版本v2的信息")
            else:
                return Response("根本就匹配不到这个路由")
    

DRF认证组件

认证的作用

有些网站内容,我们并不希望没有认证的人观看,比如购物网站,类似购物车和结算界面

我们要设置认证,只有你登录了,才可以进行接下来的操作,由于http的无状态,每一次请求都是

新的请求,所以服务器有必要对每次的请求进行认证,一般情况下后端都是把token值放到cookie里,

浏览器访问的时候携带token,服务器通过token就可以达到识别的效果,从而认证

认证怎么用

上面讲版本的时候我们知道,在dispatch方法里,执行了initial方法那里初始化了我们的版本

如果我们细心我们能看到版本的下面其实就是我们的认证,权限,频率组件了

我们先看看我们的认证组件

我没在这里反复的截图跳转页面,因为这几个组件都是在initial里封装的,自己仔细去康康就行了

我们通过上面基本可以知道我们的认证类一定要实现的方法以及返回值类型以及配置的参数authentication_classes

认证组件的用法

我们先写个认证的demo,我们先建一个用户表字段为用户名以及对应的token值

# 先在model中注册模型类
# 并且进行数据迁移
# 测试我就简写了~
# models
class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    token = models.UUIDField()
# 写视图类并且用post请求注册一个用户
# views
class UserView(APIView):
    def post(self, request, *args, **kwargs):
        username = request.data["username"]
        UserInfo.objects.create(username=username, token=uuid.uuid4())
        return Response("注册成功")

准备工作做好了

# 注意我们这个认证的类必须实现的方法以及返回值
# 这里必须要继承BaseAuthentication,不然会报错
class MyAuth(BaseAuthentication):
	# 正常来说是从cookie里拿,这里为了方便,就把token放到url上了
    def authenticate(self, request):
        request_token = request.query_params.get("token", None)
        if not request_token:
            raise AuthenticationFailed({"code": 1001, "error": "缺少token"})
        token_obj = UserInfo.objects.filter(token=request_token).first()
        if not token_obj:
            raise AuthenticationFailed({"code": 1001, "error": "无效的token"})
        return token_obj, request_token
# 视图级别的控制
class TestAuthView(APIView):
    authentication_classes = [MyAuth, ]

    def get(self, request, *args, **kwargs):
        return Response("测试认证")
    
# 全局控制
REST_FRAMEWORK = {
    # 配置全局认证
    'DEFAULT_AUTHENTICATION_CLASSES': ["BRQP.utils.MyAuth", ]
}

参考链接

https://www.cnblogs.com/GGGG-XXXX/articles/9681444.html

posted @ 2020-06-08 16:23  WillWeson  阅读(238)  评论(0编辑  收藏  举报