一 前言
之前在 Django-restframework 的流程分析博客中, 把最重要的关于认证, 权限和频率的方法找到了. 该方法是 APIView 的一个名为 initial 的类方法, 也就是在 views 中定义的视图类方法, 继承自 APIView 方法. 该方法源码如下:
那么当代码执行到这里时, 最开始执行的是用户的认证, 也就是 perform_autnentication 方法. 下面来深入的分析一下在用户认证中具体是怎么执行的.
二 用户认证执行流程
进入查看该方法源码如下:
1. 执行 APIView.perform_authentication
2. 执行 Request.user
3. 执行 Request._authenticate
4. Request.authenticators
5. APIView.initialize_request
6. APIView.get_authticators
7. api_settings.DEFAULT_AUTHENTICATION_CLASSES
到这里就是查找 APIView 配置的问题了, 后面的 DEFAULT_AUTHENTICATION_CLASSES 是默认的认证类, 该类定义在 settings.py 文件中. 之后我会写一篇 Django 加载项目配置的博客, 到时候详细分析一下, 这会涉及到 python 的两种加载文件的方式, 一种是 import; 一种是使用 importlib 模块导入.
三 自定义认证组件
了解了 restframework 的认证流程, 对于需要自定义认证组件其实很明了, 就是自定义认证类, 重写 authenticate 方法. 不过这还不行, 我们还需要进行一下配置.
需求: 在之前的项目中, 我们需要在服务器中保存相关的 cookie 或 session 来进行用户身份校验, 那么如何使用 restframework 的认证来实现该需求, 使得既能校验身份, 也可以不用在服务端保存用户的 cookie 或 session.
首先不管 cookie 或 session 都是为了校验用户的, 那么在这里我们可以使用一个随机字符串 (加密后的), 当客户端朝服务端发送请求时会携带该值, 之后进行反解用来对比.
1. urls.py
url(r'^login/', views.Login.as_view()),
2. Views.py
- # 获取 随机 token 值
- def get_token(id, salt='123'):
- md = hashlib.md5()
- md.update(bytes(str(id), encoding='utf-8'))
- md.update(bytes(salt, encoding='utf-8'))
- return md.hexdigest() + '|' + str(id)
- # 登陆视图类
- class Login(APIView):
- # def dispatch(self, request, *args, **kwargs):
- # return super(Login, self).dispatch(request, *args, **kwargs)
- def post(self, request):
- response = {'status': 100, 'msg': None}
- name = request.data.get('name')
- password = request.data.get('password')
- print(name, password)
- user_obj = models.UserInfo.objects.filter(name=name, password=password).first()
- if user_obj:
- token = get_token(user_obj.pk)
- response['msg'] = '登陆成功'
- response['status'] = 100
- response['token'] = token
- print('111', token)
- else:
- response['msg'] = '用户名或密码错误'
- return Response(response)
3. authenticate_classes.py
- # 校验 token
- def check_token(token, salt='123'):
- ls = token.split('|')
- md = hashlib.md5()
- md.update(bytes(ls[-1], encoding='utf-8'))
- md.update(bytes(salt, encoding='utf-8'))
- if md.hexdigest() == ls[0]:
- return True
- else:
- return False
- # 改写的认证类
- class BookAuth(BaseAuthentication):
- def authenticate(self, request):
- token = request.data.get('token')
- print('222', token)
- if token:
- succ = check_token(token)
- if succ:
- print('333')
- # user =
- return
- else:
- raise NotAuthenticated('认证失败')
- else:
- raise NotAuthenticated('请先登录')
四 配置自定义认证类
1. 局部配置
假设一个功能需要登陆成功才可以使用, 那么只需要在该视图类中定义一个参数 authentication_classes
- class Book(APIView):
- # 配置该参数可以局部使用
- authentication_classes = [authticate_classes.BookAuth, ]
- def dispatch(self, request, *args, **kwargs):
- return super().dispatch(request, *args, **kwargs)
- def get(self, request, id):
- print(request.user, '444')
- response = {'status': 100, 'msg': None}
- book_obj = models.Book.objects.filter(pk=id).first()
- if book_obj:
- book_ser = myser.BookSer(book_obj, many=False)
- response['book'] = book_ser.data
- else:
- response['msg'] = '图书没有对象'
- response['status'] = 101
- return Response(response)
2. 全局使用
全局使用的话需要在项目 settings 中配置, 如下:
- REST_FRAMEWORK={
- "DEFAULT_AUTHENTICATION_CLASSES":["app01.authenticate_classes.BookAuth",]
- }
这样对 views 中所有的请求方法都有效. 因为所有的视图类都会加载 settings 中的配置. 这些都是在 dispatch 方法中完成的.
3. 局部禁用
局部禁用的话只需要在视图类中定义一个空的 authentication_classes.
authentication_classes = []
来源: https://www.cnblogs.com/zuanzuan/p/10433109.html