权限和认证源码解析:
上回讲到dispatch的核心是认证与权限,现在我们来分析一下这两者之间的源码:
self.perform_authentication(request)
self.check_permissions(request)
执行认证:
def perform_authentication(self, request):
"""
Perform authentication on the incoming request.
Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user
# property可以将方法转换为属性
@property
def user(self):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes provided to the request.
"""
# 如果你没有user.
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
@user.setter
def user(self, value):
"""
Sets the user on the current request. This is necessary to maintain
compatibility with django.contrib.auth where the user property is
set in the login and logout functions.
Note that we also set the user on Django's underlying `HttpRequest`
instance, ensuring that it is available to any middleware in the stack.
"""
self._user = value
self._request.user = value
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()
将所有的认证器都遍历了一遍,然后调用每个认证器的认证方法,认证成功返回一个两位的元组,如果异常或为空都是认证失败。认证成功会将结果拆包存到self上面,即request。
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
创建authentications.py >
class TokenAuthentication(BaseAuthentication):
# Authenticate the request and return a two-tuple of (user, token).
def authenticate(self, request):
try:
# 查询参数:querry_params == 以前的 "GET"
token = request.query_params.get("token")
# 缓存中拿token
user_id = cache.get(token)
user = User.objects.get(pk=user_id)
# 认证成功
return user,token
except Exception as e:
print(e)
# 认证失败
return
view.py >
from 0.0 import TokenAuthentication
class UserView(GenericAPIView):
# 获取结果集
queryset = Cart.objects.all()
# 将数据库序列化
serializer_class = CartSerializer
# 获取认证
authentication_classes = TokenAuthentication,
def get(self, request, *args, **kwargs):
print(request.user) # 判断是不是我们库里的用户,游客用户是AnonymosUser
data = {
"msg": "登录成功",
}
return Response(data)
检查权限:
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
如果没有权限,权限被拒绝。
class BasePermission(metaclass=BasePermissionMetaclass):
"""
A base class from which all permission classes should inherit.
"""
def has_permission(self, request, view):
"""
Return `True` if permission is granted, `False` otherwise.
"""
# 如果授予权限,则返回“True”,否则返回“False”。
return True
def has_object_permission(self, request, view, obj):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
创建 permissions.py >
from rest_framework.permissions import BasePermission
from App.models import User
class LoginPermission(BasePermission):
def has_permission(self, request, view):
# 只针对get请求
if request.method == "GET":
# request.user 是我们自己的User,拥有权限,其他就是没有权限
return isinstance(request.user,User)
return True
view.py >
class UserView(GenericAPIView):
# 获取结果集
queryset = Cart.objects.all()
# 将数据库序列化
serializer_class = CartSerializer
# 获取认证
authentication_classes = TokenAuthentication,
# 获取权限
permission_classes = LoginPermission,
def get(self, request, *args, **kwargs):
serializer = UserSerializser(request.user)
data = {
"msg": "登录成功",
"data": serializer.data
}
return Response(data)