认证流程源码分析
认证流程分析:
def dispatch(self, request, *args, **kwargs):
# step 1
request = self.initialize_request(request, *args, **kwargs)
try:
self.initial(request, *args, **kwargs)
# step 2
def initialize_request(self, request, *args, **kwargs):
return Request(
request,
authenticators=self.get_authenticators(),
)
# 2.1、Request类
self.authenticators = authenticators or ()
# step 3:获取auth认证类实例化对象列表
def get_authenticators(self):
return [auth() for auth in self.authentication_classes]
class APIView(View):
# 默认的认证类,可以在类中定义此变量
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
# step 4
try:
self.initial(request, *args, **kwargs)
# step 5
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
# step 6:
def perform_authentication(self, request):
request.user
# step 7
class Request(object):
def __init__(self, request, authenticators=None):
self.authenticators = authenticators or ()
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate() # 调用
return self._user
# step 8:读取认证对象列表
def _authenticate(self):
for authenticator in self.authenticators:
try:
# 对每个进行验证,异常则全部终止,若返回None,则继续循环
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()
获取默认的认证类:
from rest_framework.views import APIView
from django.shortcuts import HttpResponse
class UserView(APIView):
def get(self,request,*args,**kwargs):
self.dispatch
print(request.version)
print(self.authentication_classes) # self为 UserView 实例对象
'''
# 默认认证类:[
rest_framework.authentication.SessionAuthentication,
rest_framework.authentication.BasicAuthentication
]
'''
return HttpResponse('....')
默认的认证类代码:
# 默认的认证类
from rest_framework.authentication import SessionAuthentication,BasicAuthentication
class SessionAuthentication(BaseAuthentication):
def authenticate(self, request):
user = getattr(request._request, 'user', None)
if not user or not user.is_active:
return None
self.enforce_csrf(request)
return (user, None)
class BasicAuthentication(BaseAuthentication):
def authenticate(self, request):
return (user, None)
自定义认证规则
示例:
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
USERTOKEN_LIST = [
'rqwtashash',
'cvjkdfdfod'
]
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
# 以url传递认证信息
tk = request._request.GET.get('tk') # 获取认证信息
if tk in USERTOKEN_LIST:
return ('kate',None)
# return None # 返回匿名用户
else:
# 自定义认证失败信息
raise exceptions.AuthenticationFailed('认证失败!')
class UserView(APIView):
# 局部指定认证类
authentication_classes = [MyAuthentication,] # 优先当在前类取此认证类
修改默认匿名用户为None:
# 若没有指定,则登录失败默认request.user=AnonymousUser
# settings.py
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER":None, # 登录失败则用户为None
'UNAUTHENTICATED_TOKEN':None,
}
利用继承关系定制继承类:
class Auth(object):
"""用来继承使用自定制的类"""
authentication_classes = [CustomAuthentication, ]
class LoginView(Auth, APIView):
# 在LoginView示例再认证时会优先进入Auth类搜索authentication_classes变量
pass
认证扩展之token认证
1、创建表:
from django.db import models
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
email = models.CharField(max_length=64)
class Token(models.Model):
value = models.CharField(max_length=64) # session_key
user = models.OneToOneField(UserInfo) # 只能登陆一次,再次登陆则会重新生成token值
# 迁移
makemigrations
migrate
2、路由配置:
from django.conf.urls import url
from app01.views import LoginView
urlpatterns = [
url(r'^login/', LoginView.as_view()),
]
3、视图:
def get_token(username):
"""生成token值"""
import time
import hashlib
hash = hashlib.md5(username.encode('utf-8'))
hash.update(str(time.time()).encode('utf-8'))
return hash.hexdigest()
class LoginView(APIView):
def post(self,request,*args,**kwargs):
"""根据用户提交的验证信息,若通过验证,则生成或者更新对应的token值"""
username = request.data.get('username')
password = request.data.get('password')
ret = {'code':1000,'msg':None}
from .models import UserInfo,Token
user = UserInfo.objects.filter(username=username,password=password).first()
if user:
value = get_token(username)
# 根据user查询,若没找到则创建,找到则更新defaults内容
Token.objects.update_or_create(user=user,defaults={'value':value})
ret['code'] = 1001
ret['token'] = value
else:
ret['msg'] = '用户名或密码错误'
return JsonResponse(ret)
3、更新或创建token测试:
# 先安装requests模块
pip install requests
import requests
response = requests.post(
url='http://127.0.0.1:8000/login/',
data={'username':'alex1','password':'abc123'}
)
print(response.text)
# 登陆错误 {"code": 1000, "msg": "\u7528\u6237\u540d\u6216\u5bc6\u7801\u9519\u8bef"}
# 登陆成功 {"code": 1001, "msg": null, "token": "9c4cb1631b3a5ead33fb09f6349c4bc7"}
4、设置认证类:
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
# 以url传递认证信息
tk = request._request.GET.get('tk') # 获取认证信息
from app01.models import Token
token_obj = Token.objects.filter(value=tk).first()
if token_obj:
return (token_obj.user, token_obj)
else:
raise exceptions.AuthenticationFailed('认证失败!')
5、利用继承指定使用的认证类:
class Auth(object):
# 优先当在前类取此变量
authentication_classes = [MyAuthentication,]
6、视图:
class UserView(Auth,APIView):
# 在调用get函数会调用Auth中指定的认证类进行相关验证
def get(self,request,*args,**kwargs):
print(request.user) # 直接取出用户对象
return HttpResponse('....')
7、路由:
from django.conf.urls import url
from app01.views import UserView
urlpatterns = [
url(r'^users/', UserView.as_view()),
8、测试:
# 浏览器输入:http://127.0.0.1:8000/users/?tk=value
# 只有携带符合条件的tk值才会通过认证,进入相应的视图