视图:
class TestAPIView(APIView):
authentication_classes=[MyJWTAuthentication]
permission_classes = [AdminPermission,]
def get(self,request)
return Respponse({'code':200,'msg':'测试通过'})
路由:
path('test/',views.TestAPIView.as_view())
请求方式:GET
认证的配置:
#1、全局配置:settings.py
REST_FRAMEWORK = {
#1、全局认证
'DEFAULT_AUTHENTICATION_CLASSES':['authen.authentication.MyJWTAuthentication'],
#2、全局的权限
'DEFAULT_PERMISSION_CLASSES':['authen.permission.AdminPermission']
}
#2、局部配置:视图类的类变量
class TestAPIView(APIView):
authentication_classes=[MyJWTAuthentication]
permission_classes = [AdminPermission]
token:
import jwt
from django.conf import settings
import time
def create_token(user_id: int, timeout=None):
'''
:param user_id: 传递用户的id
:param timeout: token有效时间,默认是一天
:return:
'''
has_exp = hasattr(settings,'JWT_EXPIRATION_DELTA')
if has_exp:
jwt_exp = getattr(settings,'JWT_EXPIRATION_DELTA')
else:
jwt_exp = 24*60*60
if timeout == None:
#没有指定过期时间,就使用配置的时间戳
timeout = jwt_exp
elif type(timeout) != int:
#传递的类型有误,使用配置中的时间戳
timeout = jwt_exp
payload = {'user_id': user_id}
salt = settings.SECRET_KEY # 加密的盐
# 构造header
headers = {
'type': 'jwt',
'alg': 'HS256'
}
now_datetime = time.time()
payload['exp'] = now_datetime + timeout # token过期时间,时间戳
# print(payload)
token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode('utf-8')
return token
认证类的书写:
from rest_framework.authentication import BaseAuthentication
class MyJWTAuthentication(BaseAuthentication):
def authenticate(self, request):
# 获取token
token = request.META.get("HTTP_TOKNE") # 从请求头中获取
if not token:
token = request.COOKIES.get('token') # 从cookies中获取token
if not token:
msg = '没有携带token'
raise AuthenticationFailed({'code':410,'error':'没有携带token'})
'''
1、切割
2、解密第二段/判断过期
3、验证第三段合法性
'''
# 导入settings中的字符串做盐
salt = settings.SECRET_KEY
payload = None
try:
payload = jwt.decode(token, salt, True)
#获取用户信息
user = models.UserModel.objects.filter(id=payload.get('user_id'),is_enable=True).first()
if user:
return (user, token)
# request.user,request.auth
else:
raise AuthenticationFailed({'code':410,'error':'token有问题'})
except exceptions:
msg = 'token有问题,请重新登录'
raise AuthenticationFailed({'code': 410, 'error': msg})
权限类书写:
from rest_framework.permissions import BasePermission
from rest_framework import exceptions
from django.contrib.auth.models import AnonymousUser
class AdminPermission(BasePermission):
message='当前用户没有管理员权限'
def has_permission(self,request,view):
#view是视图类的对象,拿到视图类的东西
#拿到token解析出来的用户的权限
user = request.user
if type(user) == AnonymousUser or user==None:
self.message = '没有携带token'
return False
if user.role == 1:
#权限是1,管理员时,才能访问接口
return True
else:
#其他权限无法访问
return False
1、TestAPIView的as_view方法,当前实例对象没有,找父类的APIView的as_view
@classmethod
def as_view(cls, **initkwargs):
#1、调用APIView父类的as_view方法
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
#2、去除掉csrf校验
return csrf_exempt(view)
2、APIView的as_view是调用父类View的as_view方法
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
return view
#返回的是闭包view,
#view的功能就是self.dispatch()方法
3、as_view主要返回闭包,关于self.dispatch()方法
4、self是TestAPIView , 没有dispatch方法,调用父类APIView的dispatch方法
#简化后的源码
def dispatch(self, request, *args, **kwargs):
#处理url中的参数
self.args = args
self.kwargs = kwargs
#构建drf的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
#认证、权限、限流的执行
self.initial(request, *args, **kwargs)
#通过反射来执行TestAPIView中的get、post等方法
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
5、self.initialize_request,TestAPIView没有,调用APIView的initialize_request方法,构建drf的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
)
5.1、self.get_authenticators(),TestAPIView没有,调用父类的APIView的get_authenticators
def get_authenticators(self):
return [auth() for auth in self.authentication_classes]
5.2、 self.authentication_classes : self=TestAPIView的实例对象
如果TestAPIView中设置了authentication_classes 成员变量
class TestAPIView(APIView):
authentication_classes=[MyJWTAuthentication]
def get(self,request)
return Respponse({'code':200,'msg':'测试通过'})
如果TestAPIView没有设置,就去父类APIView中获取
class APIView(View):
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
#这里就是去settings.py中获取配置
REST_FRAMEWORK = {
#1、全局认证
'DEFAULT_AUTHENTICATION_CLASSES':['authen.authentication.MyJWTAuthentication'],
}
5.3、获取到的就是[认证类(),]
5.4、新的request的初始化:drf的request对象,其实例变量authenticators=[认证类(),]
class Request:
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request
self.authenticators = authenticators or ()
6、self.initial(request,),TestAPIView中没有,找APIView的initial方法,
def initial(self, request, *args, **kwargs):
#认证、权限、限流
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
7、self.perform_authentication(request), TestAPIView中没有,找APIView的perform_authentication方法
#request 是drf的request,调用request的user
def perform_authentication(self, request):
request.user
8、request是drf创建的request对象,调用request.user方法(此后,就是去找Request类了)
from rest_framework.request import Request
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
在实例化request对象时,初始化中没有_user的成员变量
执行self._authenticate()方法,request的self._authenticate()方法
#self=request
def _authenticate(self):
#去Request的authenticators 实例变量中获取认证类对象类别
for authenticator in self.authenticators:
try:
#执行authenticate方法,返回元组,(user,token)
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
#认证不通过时,就是给request.user,request.auth 设置匿名用户了
self._not_authenticated()
9、认证时,token没有异常:就进入下一步了
def initial(self, request, *args, **kwargs):
# Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
10、self.check_permissions(request) 方法,TestAPIView没有,找父类APIView的check_permissions方法
def check_permissions(self, request):
for permission in self.get_permissions():
if not permission.has_permission(request, self):
#抛出异常错误
self.get_permissions(),TestAPIView没有,找APIView的get_permissions()
def get_permissions(self):
return [permission() for permission in self.permission_classes]
self.permission_classes
结果:返回[权限对象1,权限对象2,…]
循环遍历[权限对象1,权限对象2,…], 执行权限对象.has_permission方法
11、假设所有权限对象都通过了
def dispatch(self, request, *args, **kwargs):
#处理url中的参数
self.args = args
self.kwargs = kwargs
#构建drf的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
#认证、权限、限流的执行
self.initial(request, *args, **kwargs)
#通过反射来执行TestAPIView中的get、post等方法
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
12、使用反射,TestAPIView的get方法,执行后,获取返回值。
总结:
1、权限类是依赖于认证类的完成,没有设置认证的视图,就不应该设置权限类
2、权限类的流程,大致跟认证差不多的