DRF之版本控制、認證和權限組件
阿新 • • 發佈:2018-12-13
object amp sed uuid int exception acc 獲取版本 版本信息 request.versioning_scheme是實現版本控制的類的實例化對象
一、版本控制組件
1、為什麽要使用版本控制
首先我們開發項目是有多個版本的
當我們項目越來越更新,版本就越來越多,我們不可能新的版本出了,以前舊的版本就不進行維護了
像bootstrap有2、3、4版本的,每個版本都有它對應的url,https://v2.bootcss.com/ 、 https://v3.bootcss.com/
這就需要我們對版本進行控制,這個DRF也給我們提供了一些封裝好的版本控制方法
2、原理
1.
在DRF框架中,它默認幫我們設置了版本信息在request.version和request.versioning_scheme中,
只是DRF默認的版本信息是None,我們需要重寫一些配置,讓request.version攜帶上我自定義的版本信息
2.
CBV視圖函數都是首先會去執行as_view方法的,as_view會找到路由的分發方法dispatch,在真正分發之前會執行initial方法
3、使用
0. 在哪裏取版本信息 我們的版本類必須重寫determine_version這個方法,request.version就是拿它的返回值 在視圖中就可以使用request.version取到版本信息 1. 新建一個py文件 我建在utils文件夾下的version.py 在version.py下重寫一個MyVersion類 註意:必須重寫determine_version這個方法,因為request.version就是拿它的返回值class MyVersion(object): def determine_version(self,request, *args, **kwargs): version = request.query_params.get("version", "v1") return version 2. 去項目的settings配置 # 覆蓋DRF原本的配置DEFAULT_VERSIONING_CLASS,讓它的值指向我們寫的那個類 REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘utils.version.MyVersion‘ } 3. 在視圖中使用 class VersionView(APIView): def get(self, request): print(request.version) print(request.versioning_scheme) if request.version == ‘v1‘: return Response("v1版本") elif request.version == ‘v2‘: return Response(‘v2版本‘) return Response(‘不存在的版本‘)
4、DRF的versioning模塊
1. 在這裏模塊內給我們配置了各種獲取版本的類 2. versioning模塊
# 基礎類 class BaseVersioning(object): 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 """ # 在URL中攜帶版本信息 class URLPathVersioning(BaseVersioning): ‘‘‘ 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‘) ] ‘‘‘ # 在namespace中攜帶版本信息 class NamespaceVersioning(BaseVersioning): ‘‘‘ # 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‘)) ] ‘‘‘ # 在域名中攜帶版本信息 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 """version模塊的類
3. 基礎類的三個配置 REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘utils.version.MyVersion‘, # 默認版本 ‘default_version‘: ‘v1‘, # 可用版本 ‘allowed_versions‘: [‘v1‘, ‘v2‘], # 參數 ‘version_param‘: ‘version‘, }
4. 使用DRF的版本控制 方法一 1. 在utils文件夾下的version.py繼承versioning的類 from rest_framework import versioning class MyVersion(versioning.URLPathVersioning): pass 2. urls.py urlpatterns = [ # url(r‘^version_demo/‘, views.VersionView.as_view()), url(r‘^(?P<version>[v1|v2]+)/version_demo/‘, views.VersionView.as_view()), ] 3. settings.py REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘utils.version.MyVersion‘, # 默認版本 ‘default_version‘: ‘v1‘, # 可用版本 ‘allowed_versions‘: [‘v1‘, ‘v2‘], # 參數 ‘version_param‘: ‘version‘, } 4.在視圖中使用需要接收參數version class VersionView(APIView): def get(self, request, version): print(request.version) print(request.versioning_scheme) if request.version == ‘v1‘: return Response("v1版本") elif request.version == ‘v2‘: return Response(‘v2版本‘) return Response(‘不存在的版本‘) 5. 在瀏覽器中 可以輸入: v1/version_demo/ v2/version_demo/ 方法二 其他步驟基本一樣,只是我們在配置的時候直接指定某個類 1. urls.py urlpatterns = [ # url(r‘^version_demo/‘, views.VersionView.as_view()), url(r‘^(?P<version>[v1|v2]+)/version_demo/‘, views.VersionView.as_view()), ] 2. settings.py REST_FRAMEWORK = { ‘DEFAULT_VERSIONING_CLASS‘: ‘rest_framework.versioning.URLPathVersioning‘, # 指定URLPathVersioning這個類 # 默認版本 ‘default_version‘: ‘v1‘, # 可用版本 ‘allowed_versions‘: [‘v1‘, ‘v2‘], # 參數 ‘version_param‘: ‘version‘, }
二、認證
1、為什麽要認證
我們可以在網站上登錄,然後可以有個人中心,對自己信息就行修改
但是我們每次給服務器發請求,由於Http的無狀態,導致我們每次都是新的請求
那麽服務端需要對每次來的請求進行認證,看用戶是否登錄,以及登錄用戶是誰
那麽我們服務器對每個請求進行認證的時候,不可能在每個視圖函數中都寫認證
一定是把認證邏輯抽離出來,以前我們可能會加裝飾器,或者中間件,DRF框架也有它的認證
2、原理
在前端進行登錄的時候,用戶名和密碼輸入正確後,後端根據用戶名和密碼拿到這個用戶的一些信息(用戶名,性別等),
把這些信息加密後生成一個隨機字符串token返回給前端,
前端下次請求再來的時候,帶上這個隨機字符串,後端根據自己的解密算法再算出來,實現認證。
3、token認證
0. 在哪裏取認證的信息 我們的認證類必須重寫authenticate這個方法,返回值是元組 第一個值賦值給了request.user, 第二個賦值給request.auth 在視圖中就可以使用request.user和request.auth取到認證的信息 1. models.py class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 用UUID字符串存隨機字符串 token = models.UUIDField(null=True, blank=True) CHOICES = ((1, "vip"), (2, "普通用戶"), (3, "vvip")) 2. settings配置 # 跟版本一樣,覆蓋原本的配置,使用自己的配置 REST_FRAMEWORK = { # 配置認證類 # 這樣配是全局,所有路由都要認證 ‘DEFAULT_AUTHENTICATION_CLASSES‘:[‘utils.auth.MyAuth‘, ] } 3. utils/auth.py from rest_framework import authentication from AuthDemo.models import User from rest_framework.exceptions import AuthenticationFailed class MyAuth(authentication.BaseAuthentication): # 必須重寫authenticate這個方法,返回值是元組 # 第一個值賦值給了request.user, 第二個賦值給request.auth def authenticate(self, request): # 獲取前端攜帶的token,看token是否合法 token = request.query_params.get("token", "") if not token: raise AuthenticationFailed("沒有攜帶token") user_obj = User.objects.filter(token=token).first() # 返回需要的信息 if user_obj: return (user_obj, token) # 驗證不通過,拋出異常 raise AuthenticationFailed("token不合法") 4. 視圖 class TestView(APIView): def get(self, request): print(request.user) print(request.auth) return Response("登陸後發送的數據") 5. 局部配置 1. 如果只是某些路由需要認證,那麽可以局部設置認證,包括版本也可以局部認證 2. 把settings的配置註釋掉 3. 在需要認證的視圖中聲明 from utils.auth import MyAuth class TestView(APIView): authentication_classes = [MyAuth, ] # 局部配置認證組件 # versioning_class = [] # 局部配置版本組件 def get(self, request): print(request.user) print(request.auth) return Response("登陸後發送的數據")
DRF之版本控制、認證和權限組件