欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

django drf框架中的user驗證以及JWT拓展的介紹

 更新時間:2019年08月12日 08:27:02   作者:志浩hzh  
這篇文章主要介紹了django drf框架中的user驗證以及JWT拓展的介紹,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

登錄注冊是幾乎所有網(wǎng)站都需要去做的接口,而說到登錄,自然也就涉及到驗證以及用戶登錄狀態(tài)保存,最近用DRF在做的一個關(guān)于網(wǎng)上商城的項目中,引入了一個拓展DRF JWT,專門用于做驗證和用戶狀態(tài)保存。這個拓展比傳統(tǒng)的CSRF更加安全。先來介紹一下JWT認證機制吧!

Json web token (JWT), 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標準( (RFC 7519 ).該token被設(shè)計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。

基于token的鑒權(quán)機制

基于token的鑒權(quán)機制類似于http協(xié)議也是無狀態(tài)的,它不需要在服務(wù)端去保留用戶的認證信息或者會話信息。這就意味著基于token認證機制的應(yīng)用不需要去考慮用戶在哪一臺服務(wù)器登錄了,這就為應(yīng)用的擴展提供了便利。

流程上是這樣的:

  • 用戶使用用戶名密碼來請求服務(wù)器
  • 服務(wù)器進行驗證用戶的信息
  • 服務(wù)器通過驗證發(fā)送給用戶一個token
  • 客戶端存儲token,并在每次請求時附送上這個token值
  • 服務(wù)端驗證token值,并返回數(shù)據(jù)

這個token必須要在每次請求時傳遞給服務(wù)端,它應(yīng)該保存在請求頭里, 另外,服務(wù)端要支持 CORS(跨來源資源共享) 策略,一般我們在服務(wù)端這么做就可以了 Access-Control-Allow-Origin: * 。

那么我們現(xiàn)在回到JWT的主題上。

JWT的構(gòu)成

第一部分我們稱它為頭部(header),第二部分我們稱其為載荷(payload, 類似于飛機上承載的物品),第三部分是簽證(signature).

jwt的頭部承載兩部分信息:1,聲明類型,這里是jwt,2聲明加密的算法 通常直接使用 HMAC SHA256。完整的頭部就像下面這樣的JSON:

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

然后將頭部進行base64加密(該加密是可以對稱解密的),構(gòu)成了第一部分。

如 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9。

載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分1標準中注冊的聲明,2公共的聲明,3私有的聲明。標準中注冊的聲明 (建議但不強制使用) :1 iss: jwt簽發(fā)者,2 sub: jwt所面向的用戶,3 aud: 接收jwt的一方,4 exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間,5 nbf: 定義在什么時間之前,該jwt都是不可用的,6 iat: jwt的簽發(fā)時間,7 jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。公共的聲明 : 公共的聲明可以添加任何的信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.私有的聲明 : 私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。定義一個payload:

{
 "sub": "1234567890",
 "name": "John Doe",
 "admin": true
}

然后將其進行base64加密,得到JWT的第二部分。

如 eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9。

JWT的第三部分是一個簽證信息,這個簽證信息由三部分組成:1 header (base64后的),2 payload (base64后的),3 secret。這個部分需要base64加密后的header和base64加密后的payload使用 . 連接組成的字符串,然后通過header中聲明的加密方式進行加鹽 secret 組合加密,然后就構(gòu)成了jwt的第三部分。

注意:secret是保存在服務(wù)器端的,jwt的簽發(fā)生成也是在服務(wù)器端的,secret就是用來進行jwt的簽發(fā)和jwt的驗證,所以,它就是你服務(wù)端的私鑰,在任何場景都不應(yīng)該流露出去。一旦客戶端得知這個secret, 那就意味著客戶端是可以自我簽發(fā)jwt了。

首先需要安裝拓展  pip install djangorestframework-jwt,然后在django進行配置, JWT_EXPIRATION_DELTA 指明token的有效期。

REST_FRAMEWORK = {
 'DEFAULT_AUTHENTICATION_CLASSES': (
  'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
  'rest_framework.authentication.SessionAuthentication',
  'rest_framework.authentication.BasicAuthentication',
 ),
}

JWT_AUTH = {
 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
}

Django REST framework JWT 擴展的說明文檔中提供了手動簽發(fā)JWT的方法

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)

在注冊時,引入上述代碼,簽發(fā)JWT即可。而對于登錄,JWT拓展提供了內(nèi)置的視圖,在urls中添加對于路由即可。

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
 url(r'^authorizations/$', obtain_jwt_token),
]

雖然寫起來很簡單,但是內(nèi)部其實做了很多的事,今天就來詳細研究一下,源代碼內(nèi)部做了哪些事情。

當用戶登錄,會以post形式發(fā)請求到后端,會訪問 obtain_jwt_token中的post方法,在源代碼中可以看到 obtain_jwt_token = ObtainJSONWebToken.as_view(),跟我們寫的類視圖十分類似,這是一個內(nèi)部已經(jīng)寫好的類視圖。

class ObtainJSONWebToken(JSONWebTokenAPIView):
 """
 API View that receives a POST with a user's username and password.

 Returns a JSON Web Token that can be used for authenticated requests.
 """
 serializer_class = JSONWebTokenSerializer

該類并未定義任何方法,所以對應(yīng)的post方法應(yīng)該寫在父類,下面是父類中的post方法

def post(self, request, *args, **kwargs):
  serializer = self.get_serializer(data=request.data)

  if serializer.is_valid():
   user = serializer.object.get('user') or request.user
   token = serializer.object.get('token')
   response_data = jwt_response_payload_handler(token, user, request)
   response = Response(response_data)
   if api_settings.JWT_AUTH_COOKIE:
    expiration = (datetime.utcnow() +
        api_settings.JWT_EXPIRATION_DELTA)
    response.set_cookie(api_settings.JWT_AUTH_COOKIE,
         token,
         expires=expiration,
         httponly=True)
   return response

  return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

上述方法返回一個Response對象,經(jīng)過一系列操作返回到前端,訪問結(jié)束。

而在DRF框架中,在調(diào)用視圖之前,就會進行相應(yīng)的驗證操作。想要了解整個過程,需要我們從源代碼中一步步去探索。當前端發(fā)起一個請求到后端,會根據(jù)路由訪問對象的視圖類的as_view()方法,該方法會接著調(diào)用dispatch()方法,APIView是DRF中所有視圖類的父類,可以看一下他的dispatch方法。

def dispatch(self, request, *args, **kwargs):
  """
  `.dispatch()` is pretty much the same as Django's regular dispatch,
  but with extra hooks for startup, finalize, and exception handling.
  """
  self.args = args
  self.kwargs = kwargs
  request = self.initialize_request(request, *args, **kwargs)
  self.request = request
  self.headers = self.default_response_headers # deprecate?

  try:
   self.initial(request, *args, **kwargs)

   # Get the appropriate handler method
   if request.method.lower() in self.http_method_names:
    handler = getattr(self, request.method.lower(),
         self.http_method_not_allowed)
   else:
    handler = self.http_method_not_allowed

   response = handler(request, *args, **kwargs)

  except Exception as exc:
   response = self.handle_exception(exc)

  self.response = self.finalize_response(request, response, *args, **kwargs)
  return self.response

可以看到,到請求進來,會調(diào)用self.initalize_request()方法對請求進行處理。

def initialize_request(self, request, *args, **kwargs):
  """
  Returns the initial request object.
  """
  parser_context = self.get_parser_context(request)

  return Request(
   request,
   parsers=self.get_parsers(),
   authenticators=self.get_authenticators(),
   negotiator=self.get_content_negotiator(),
   parser_context=parser_context
  )

我們需要關(guān)注的只有 authenticators=self.get_authenticators()這一句,

def get_authenticators(self):
  """
  Instantiates and returns the list of authenticators that this view can use.
  """
  return [auth() for auth in self.authentication_classes]

接著往上照,可以看到類屬性 permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES,這就是要什么我們要在django配置中加入DEFAULT_PERMISSION_CLASSES配置,上述方法會遍歷我們在配置中寫到的列表,拿到里面的驗證類,并進行實例化,并將生成的對象裝在一個新的列表中,保存在新生成的Request對象中。然后我們接著看dispatch方法,在實際調(diào)用視圖類中的對應(yīng)方法前,還調(diào)用了self.initial()方法進行一些初始化操作。

def initial(self, request, *args, **kwargs):
  """
  Runs anything that needs to occur prior to calling the method handler.
  """
  self.format_kwarg = self.get_format_suffix(**kwargs)

  # Perform content negotiation and store the accepted info on the request
  neg = self.perform_content_negotiation(request)
  request.accepted_renderer, request.accepted_media_type = neg

  # Determine the API version, if versioning is in use.
  version, scheme = self.determine_version(request, *args, **kwargs)
  request.version, request.versioning_scheme = version, scheme

  # Ensure that the incoming request is permitted
  self.perform_authentication(request)
  self.check_permissions(request)
  self.check_throttles(request)

我們需要關(guān)注的是最后三排,分別調(diào)用了三個方法,進行身份驗證,權(quán)限驗證和分流操作,這里我們只關(guān)注 身份驗證方法,self.perform_authentication(),該方法內(nèi)只有一句代碼request.user,看起來像是在調(diào)用request對象的user屬性,其實不然,我們可以到DRF框架的Request對象中找到以下方法。

@property
 def user(self):
  """
  Returns the user associated with the current request, as authenticated
  by the authentication classes provided to the request.
  """
  if not hasattr(self, '_user'):
   with wrap_attributeerrors():
    self._authenticate()
  return self._user

user方法經(jīng)過property裝飾器裝飾后,就可以像一個屬性一樣調(diào)用該方法,該方法在Request對象中存在對應(yīng)的user時會直接返回,若用戶登陸時,Request對象中沒有對應(yīng)的user,所以代碼會走if判斷里面,我們只需要關(guān)注方法self._authenticate()的調(diào)用即可。

def _authenticate(self):
  """
  Attempt to authenticate the request using each authentication instance
  in turn.
  """
  for authenticator in self.authenticators:
   try:
    user_auth_tuple = authenticator.authenticate(self)
   except exceptions.APIException:
    self._not_authenticated()
    raise

   if user_auth_tuple is not None:
    self._authenticator = authenticator
    self.user, self.auth = user_auth_tuple
    return

  self._not_authenticated()

可以看到,該方法會遍歷我們在之前處理Request對象時傳入的裝著驗證類對象的列表,并調(diào)用驗證類的authenticate()方法,若驗證成功生成對應(yīng)的self.user和self.auth并直接return,往上則直接將生成的self.user進行返回,若驗證內(nèi)部出錯,會調(diào)用 self._not_ authenticated(), 并拋出錯誤,往上看,在dispatch方法中,若初始化方法出錯,則進行捕獲,并調(diào)用self.handle_exception()方法生成一個Response對象進行返回,不會執(zhí)行視圖類中對應(yīng)的方法,則調(diào)用對于的是self._not_authenticated()。

def _not_authenticated(self):
  """
  Set authenticator, user & authtoken representing an unauthenticated request.

  Defaults are None, AnonymousUser & None.
  """
  self._authenticator = None

  if api_settings.UNAUTHENTICATED_USER:
   self.user = api_settings.UNAUTHENTICATED_USER()
  else:
   self.user = None

  if api_settings.UNAUTHENTICATED_TOKEN:
   self.auth = api_settings.UNAUTHENTICATED_TOKEN()
  else:
   self.auth = None

UNAUTHENTICATED_USER在django默認配置中為一個匿名用戶的類,UNAUTHENTICATED_TOKEN默認為None,若所有驗證都為通過或者某一驗證過程中出錯,則生成一個匿名用戶,并將self.auth設(shè)置為None。

綜上所述,在請求執(zhí)行之前,DRF框架會根據(jù)我們在配置文件中配置的驗證類對用戶進行身份驗證,若未通過驗證,則會生成一個匿名用戶,驗證通過,則生成對應(yīng)的用戶。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • PyQt5 對圖片進行縮放的實例

    PyQt5 對圖片進行縮放的實例

    今天小編就為大家分享一篇PyQt5 對圖片進行縮放的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • 簡單瞅瞅Python vars()內(nèi)置函數(shù)的實現(xiàn)

    簡單瞅瞅Python vars()內(nèi)置函數(shù)的實現(xiàn)

    這篇文章主要介紹了簡單瞅瞅Python vars()內(nèi)置函數(shù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Python3邏輯運算符與成員運算符

    Python3邏輯運算符與成員運算符

    這篇文章主要介紹了Python3邏輯運算符與成員運算符,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-09-09
  • 用TensorFlow實現(xiàn)多類支持向量機的示例代碼

    用TensorFlow實現(xiàn)多類支持向量機的示例代碼

    這篇文章主要介紹了用TensorFlow實現(xiàn)多類支持向量機的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • 使用python的pandas讀取excel文件中的數(shù)據(jù)詳情

    使用python的pandas讀取excel文件中的數(shù)據(jù)詳情

    這篇文章主要介紹了使用python的pandas讀取excel文件中的數(shù)據(jù)詳情,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • Python3 SSH遠程連接服務(wù)器的方法示例

    Python3 SSH遠程連接服務(wù)器的方法示例

    這篇文章主要介紹了Python3 SSH遠程連接服務(wù)器的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • PYTHON繪制雷達圖代碼實例

    PYTHON繪制雷達圖代碼實例

    這篇文章主要介紹了PYTHON繪制雷達圖代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • python在新的圖片窗口顯示圖片(圖像)的方法

    python在新的圖片窗口顯示圖片(圖像)的方法

    今天小編就為大家分享一篇python在新的圖片窗口顯示圖片(圖像)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • Pycharm如何導(dǎo)入python文件及解決報錯問題

    Pycharm如何導(dǎo)入python文件及解決報錯問題

    這篇文章主要介紹了Pycharm如何導(dǎo)入python文件及解決報錯問題,本文通過示例截圖相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • python翻譯軟件實現(xiàn)代碼(使用google api完成)

    python翻譯軟件實現(xiàn)代碼(使用google api完成)

    這篇文章主要介紹了python結(jié)合google api完成的翻譯軟件實現(xiàn)代碼,大家參考使用
    2013-11-11

最新評論