JWT認證原理及使用

1、JWT原理:前端

  參考文章:https://www.jianshu.com/p/180a870a308aweb

  一、傳統的登陸方式:算法

    瀏覽器輸入用戶名密碼,服務端校驗經過,根據用戶信息生成一個token,將token和user_id存到數據庫或者session中,並將token返回給前端,存入cookie,後面瀏覽器每次請求都會帶上cookie,服務端根據cookie查詢用戶,驗證用戶有效性。數據庫

    弊端:django

      1)若是出現XSS(跨站腳本攻擊)漏洞,因爲cookie能夠被js讀取,XSS漏洞會致使用戶token被泄露。後端

       解決方案:瀏覽器

        a)設置httpOnly,這樣的話cookie將不會被js讀取,瀏覽器會自動將它加到請求頭信息中,可是帶來了新的問題,很容易被XSRF(跨站請求僞造)攻擊,由於只要當前瀏覽器開着,另外一個界面能夠很容易的跨站請求這個界面的內容,由於cookie會被默認發送出去。服務器

        b)設置secure,這樣cookie就只能經過https傳輸,能夠過濾掉一些使用http協議請求的XSS注入。cookie

      2)將驗證信息存到數據庫中,每次驗證的時候,都須要去數據庫中查詢,增長了數據庫的查詢和存儲開銷。session

      3)若是將token存到session中,也會增長服務器的存儲壓力。

  二、爲何使用 JWT

    1)能夠經過URL POST參數或者http header中發送,數據量小,傳輸速度快。

    2)自包含:負載中包含了用戶所須要的全部信息,避免屢次查詢數據庫。

    3)JWT組成:

      header+payload+signature 三者經過點【.】鏈接起來就是JWT了。

      

 

      a)header頭部:包含token類型和採用的加密算法

        {"alg":"HS256", "typ":"JWT"}

      b)payload負載:存放信息的地方,能夠把用戶ID等信息存放在payload中。

        經常使用的信息有:iss(簽發者), exp(過時時間), sub(面向用戶), aud(接收方), iat(簽發時間)等。

      c)signature簽名:使用編碼後(base64編碼)的header和payload再加上咱們提供的一個公鑰,而後使用header中指定的簽名算法進行簽名。做用是保證JWT沒有被竄改過。

      JWT只適合向web端傳遞一些非敏感信息,由於base64編碼是可逆的,很容易被破解。

      JWT一般用來設計用戶認證和受權系統,還有咱們一般說的單點登陸等。

 

2、JWT的使用過程

        

  1)前端經過表單將用戶名和密碼發送到後端接口。

  2)後端覈對用戶名和密碼後,將用戶的id及其餘非敏感信息做爲JWT Payload,將其與頭部分別進行base64編碼後簽名,生成JWT

    具體源代碼見rest_framework_jwt下面的serializer中,有興趣研究的能夠去跟蹤看看

    

 

  3)後端將JWT字符串做爲登陸成功的結果返回給前端,前端能夠將JWT存到localStorage或者sessionStorage中,退出登陸時,前端刪除保存的JWT信息便可。

  4)前端每次在請求時,將JWT放到header中的Authorization

  5)後端驗證JWT的有效性

  6)驗證經過後,進行其餘邏輯操做。

 

3、JWT使用方法:

  一、安裝

    pip install djangorestframework-jwt

  二、將JSONWebTokenAuthentication加到settings.py中的DEFAULT_AUTHENTICATION_CLASSES中,它能夠將用戶post過來的數據進行驗證,並將user取出來,它和MIDDLEWARE中的AuthenticationMiddleware的原理是同樣的。

    

  三、配置JWT的認證接口的url

    from djangorestframework-jwt.views import obtain_jwt_token

    url(r"^login$", obtain_jwt_token)

  四、前端訪問 login,傳入用戶名和密碼,服務器會給瀏覽器返回一段token(jwt)

    {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE1MzEzNzU4NjEsImVtYWlsIjoiMzcwMTkzNTkzQHFxLmNvbSIsInVzZXJuYW1lIjoiYWRtaW4ifQ.BIl1b68VV-LvZOu-wrUeMxUFI3IREapgqfbTtzB6Ftw"}

  五、在後面的請求中,將JWT token信息 加入到header中的authorization中。

  六、擴展:

    DRF默認是經過郵箱做爲用戶名來登陸的,因此若是咱們是經過手機或者其餘方式登陸的話,須要重寫DRF的認證方式。

    from django.db.models import Q

    from django.contrib.auth.backends import ModelBackend

    from django.contrib.auth import get_user_model

    User = get_user_model()

    class CustomBackend(ModelBackend):

      def authenticate(self, request, username=None, password=None, **kwargs):

        try:

          user = User.objects.get(Q(username=username) | Q(mobil = username))

          if user.check_password(password):

            return user

          else:

            return None 

        except Exception as e:

          return None

   七、將重寫的CustomBackend加入到settings中

    

  八、JWT的額外設置:

    

相關文章
相關標籤/搜索