django-rest-framework原始碼分析2—認證(Authentication)原始碼解析
什麼是認證(Authentication)
通俗地講就是驗證當前使用者的身份,證明 “你是你自己”(比如:你每天上下班打卡,都需要通過指紋打卡,當你的指紋和系統裡錄入的指紋相匹配時,就打卡成功)
網際網路中的認證:
- 使用者名稱密碼登入
- 郵箱傳送登入連結
- 手機號接收驗證碼
- 只要你能收到郵箱 / 驗證碼,就預設你是賬號的主人
傳統認證方式
# models
class UserInfo(models.Models):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
class UserToken(models.Models):
user = models.OneToOneField(to='UserInfo')
token = models.CharField(max_length=64)
# views
def md5(user):
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user,enceding='utf-8'))
m.update(bytes(ctime,enceding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
def post(self,request,*args,**kwargs):
ret = {"code":'1000','msg':None}
try:
user = request._request.POST.get('username')
pwd = reuqest._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=name,password=pwd).first()
if not obj:
ret['code']='1001'
ret['msg']='使用者名稱祕密錯誤'
token = md5(user)
models.UserToken.objects.update_or_create(user=obj,default={'token':token})
ret['token']=token
except Excepion as e:
ret['code']='1002'
ret['msg']='請求異常'
return JsonResponse(ret)
原始碼分析
#認證中的基類,主要實現authenticate 和 authenticate_header方法
class BaseAuthentication:
"""
All authentication classes should extend BaseAuthentication.
"""
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.")
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
#基於使用者名稱和密碼的認證
class BasicAuthentication(BaseAuthentication):
#基於session的認證
class SessionAuthentication(BaseAuthentication):
#基於token的認證
class TokenAuthentication(BaseAuthentication): ---
#遠端使用者認證
class RemoteUserAuthentication(BaseAuthentication):
"""
REMOTE_USER authentication.
To use this, set up your web server to perform authentication, which will
set the REMOTE_USER environment variable. You will need to have
'django.contrib.auth.backends.RemoteUserBackend in your
AUTHENTICATION_BACKENDS setting
"""
認證流程
authentication_classes
請求到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)
呼叫self.initial()
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
呼叫 perform_authentication() 返回request.user
def perform_authentication(self, request):
request.user
**在dispatch中initialize_request封裝了Request **
def initialize_request(self, request, *args, **kwargs):
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
)
Request 有方法註解 user 呼叫_authenticate 迴圈認證物件 執行方法
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
def _authenticate(self):
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()
使用方法
- 全域性使用
自定義的認證類可以通過全域性設定 放在setting檔案中 原始碼中會讀取setting中的
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES'=('自定義的認證類'),
'UNAUTHENTICATED_USER':None,
'UNAUTHENTICATED_TOKEN':None
}
- 區域性使用(檢視級別的認證)
內建的認證類 rest_framework.authentication BasicAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class MyAuth(BaseAuthentication):
def authenticate(self, request):
if request.method in ["POST", "PUT", "DELETE"]:
request_token = request.data.get("token", None)
if not request_token:
raise AuthenticationFailed('缺少token')
token_obj = models.Token.objects.filter(token_code=request_token).first()
if not token_obj:
raise AuthenticationFailed('無效的token')
return token_obj.user.username, None
else:
return None, None
繼承 BasicAuthentication 建立自定義的認證類 實現 authenticate方法
新增到檢視類的 authentication_classes
class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
authentication_classes = [MyAuth, ]
相關文章
- drf 認證校驗及原始碼分析原始碼
- Struts2 原始碼分析-----攔截器原始碼解析 --- ParametersInterceptor原始碼
- 友好 RxJava2.x 原始碼解析(三)zip 原始碼分析RxJava原始碼
- Laravel Passport——OAuth2 API 認證系統原始碼解析(上)LaravelPassportOAuthAPI原始碼
- Laravel Passport——OAuth2 API 認證系統原始碼解析(下)LaravelPassportOAuthAPI原始碼
- 集合原始碼分析[2]-AbstractList 原始碼分析原始碼
- ASP.NET Core[原始碼分析篇] - 認證ASP.NET原始碼
- 【Spring原始碼分析】AOP原始碼解析(上篇)Spring原始碼
- 【Spring原始碼分析】AOP原始碼解析(下篇)Spring原始碼
- shiro認證流程原始碼分析--練氣初期原始碼
- MySQL • 原始碼分析 • mysql認證階段漫遊MySql原始碼
- 【原始碼SOLO】Retrofit2原始碼解析(一)原始碼
- 【原始碼SOLO】Retrofit2原始碼解析(二)原始碼
- Django(64)頻率認證原始碼分析與自定義頻率認證Django原始碼
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- Mysql原始碼分析2MySql原始碼
- koa2原始碼解析原始碼
- Retrofit2原始碼解析原始碼
- Framework 原始碼解析知識梳理(5) startService 原始碼分析Framework原始碼
- 認真的 Netty 原始碼解析(二)Netty原始碼
- 認真的 Netty 原始碼解析(一)Netty原始碼
- ReentrantLock解析及原始碼分析ReentrantLock原始碼
- SpringSecurity認證流程原始碼詳解SpringGse原始碼
- spring security 認證原始碼跟蹤Spring原始碼
- Retrofit原始碼分析三 原始碼分析原始碼
- Redux原始碼分析(2) - createStoreRedux原始碼
- 3.24 vchain原始碼分析2AI原始碼
- RxJava2原始碼分析RxJava原始碼
- HashMap從認識到原始碼分析HashMap原始碼
- RxJava2 原始碼解析(一)RxJava原始碼
- Retrofit2原始碼解析(一)原始碼
- Promise-Polyfill原始碼解析(2)Promise原始碼
- RxJava2 原始碼解析(二)RxJava原始碼
- underscore.js原始碼解析2JS原始碼
- ptmalloc2原始碼解析初探原始碼
- mina2原始碼解析原始碼
- Spark原始碼-SparkContext原始碼解析Spark原始碼Context
- 容器類原始碼解析系列(三)—— HashMap 原始碼分析(最新版)原始碼HashMap