互联网中的认证:
- 用户名密码登录
- 邮箱发送登录链接
- 手机号接收验证码
- 只要你能收到邮箱 / 验证码,就默认你是账号的主人
传统认证方式
# 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()