Django REST Framework之認證組件

什麼是認證

認證即須要知道是誰在訪問服務器,須要有一個合法身份。認證的方式能夠有不少種,例如session+cookie、token等,這裏以token爲例。若是請求中沒有token,咱們認爲這是未登陸狀態,有些接口要求必須登陸才能訪問,若是未登陸,咱們能夠一些處理(好比重定向登陸頁、返回錯誤信息等)。前端

代碼結構

urls.pypython

from django.conf.urls import url, include
from DemoApp.views import TestView
  
urlpatterns = [
    url(r'^test/', TestView.as_view()),
]

功能代碼:utils/auth.py數據庫

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed,ValidationError
from DemoApp.models import User

class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        "認證邏輯"
        # 作認證,判斷是否登錄。首先拿到token,在數據庫裏去判斷
        token = request.query_params.get("token","")
        if not token:
            raise AuthenticationFailed("沒有token")
        try:
            user = User.objects.filter(token=token).first()
            if not user:
                pass
                raise AuthenticationFailed("無效的token")
        except Exception as e:
            msg = "無效的token" if hasattr(e, "messages") else "非法的token"
            raise AuthenticationFailed(msg)

        return (user, token) # 返回值是一個元素,分別對應視圖中request的user,auth

views.pydjango

class TestView(APIView):
    authentication_classes = [MyAuth, ]  # 局部認證

    def get(self, request, *args, **kwargs):
        "經過認證後進入views類進行業務處理"
        print(request.user)
        print(request.auth)
        pass

在上述代碼中,實現了TestView視圖類的認證功能。若是認證成功,向視圖類中的request對象中返回requset.user和request.auth;若是認證失敗,觸發異常,不會進入視圖處理,直接返回前端認證失敗的結果。在實際的業務中這樣並不合適,咱們能夠將其替代成重定向操做。編程

全局認證

  1. 將視圖類中的authentication_classes屬性刪除
  2. settings.py配置文件中 RESTFRAMEWORK 添加配置
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ] # 默認使用的認證類,全局認證
}

若是在全局認證下,有些接口不想加上認證,能夠在這個類的屬性 authentication_classes = [ ] 便可。服務器

除了上述本身實現的認證類,REST Framework爲咱們了四種認證類:(直接在視圖類中使用便可)cookie

from rest_framework.authentication import BaseAuthentication, ......
1.BasicAuthentication       基於用戶名密碼
2.SessionAuthentication     基於session
3.TokenAuthentication       基於token,與示例中相似
4.RemoteUserAuthentication  

源碼分析

1.爲何要使用authentication_classes屬性變量?

  

python 的面向對象編程中,咱們首先要執行的方法確定是dispatch方法,因此咱們的分析入口就是dispatch方法,在dispatch方法中,能夠看到,經過initialize_request方法將django原生的request進行了一次封裝。由initialize_request方法的實現過程能夠看出,將其封裝實例化成了一個Request對象。而authenticators屬性就是認證屬性。session

經過查看get_authenticators方法,能夠知道,它的返回值是一個列表生成式,而這個列表生成式中所用的就是咱們在認證類中賦值authenticatin_classes屬性變量。在查找該變量的定義位置,就看到了它是經過settings配置文件來實現賦值的,除非,在子類中將其賦值。咱們的代碼就是這樣作的。同時,也能夠看出,咱們能夠修改settings配置文件來爲全局定義認證規則。源碼分析

2.爲何認證類中要使用authenticate方法?

回到前面說是的dispatch方法來,在作完了對django原生的request的封裝和實例化後,緊接着就會開始認證(try...中,捕獲異常,若是沒有捕獲到異常,說明認證成功,就會繼續執行下面的反射過程)。認證的過程就包含在上圖中的inital方法中,有圖可知,是經過perform_authentication方法實現的認證。url

在perform_authentication方法中能夠看到,只調用了一個request.user,而這個user必定是方法,不會是屬性變量,由於若是是屬性變量,那麼就必定有語法錯誤,變量必定是要賦值的,不可能孤零零的寫到那裏。咱們在源碼中找到它,就明白了,之因此它能這麼寫,就是由於有了property裝飾器。在user方法中找到_authenticate方法,這就是認證的方法。

在這個方法中,一切答案都就找到了。首先看authenticators,是否是很眼熟,沒錯它就是前面說的,封裝和實例化原生request的Request類中所定義的屬性變量。在實例化時,咱們就將authentication_classes列表的值經過get_authenticators方法中的列表生成式賦值給了authenticators。再往下看,authenticator.autheneicate(self)中的authenticator是否是就是咱們本身定義的認證類,而它在源碼中要作「.authenticate(self)」的操做,那天然而然,咱們定義的認證類中要實現這個方法了。

3.爲何認證成功後的返回值在request.user和request.auth中?

由上述圖可知,當咱們認證成功後會執行「self.user, self.auth = user_auth_tuple」代碼,咱們在認證類定義的方法authenticate的返回值就保存在 user_auth_tuple中,因此咱們經過request.user 和 request.auth 就能夠獲取到了

相關文章
相關標籤/搜索