(生鲜项目)15. drf的用户认证 (解决django自带的csrf强制用户验证)
第一节: 基本介绍
1. REST框架中, 由于是前后端分离, 所以已经是跨站点访问, 所以csrf认证也就没必要做了.
框架中的 BasicAuthentication 和 SessionAuthentication 这两个类实际上也没干啥事, 仍然是利用django本身的 SessionMiddleware 和 AuthenticationMiddleware 这两个中间件
那么, REST中的认证有什么特别的地方吗? 有! 在于其自己的 TokenAuthentication 类
2. 首先是注册app
INSTALLED_APPS = [ ... 'rest_framework.authtoken' ]
3. 使用 makemigrations 和 migrate 生成 token 表, 这个表只有3个字段, user_id 外键到我们的userprofile表
3.实际上 token 和 user 是一一对应的, 但token不会自动创建, 所以需要单独的配置, 配置如下,
每次用户注册的时候, 我们都应该调用这个函数
用户登录的时候, 也会自动生成token
from rest_framework.authtoken.models import Token token = Token.objects.create(user=...) print(token.key)
4.另外, 浏览器端的用户认证, 应该带上以下头信息
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b #中间有空格
5.最后是url的配置
from rest_framework.authtoken import views urlpatterns += [ url(r'^api-token-auth/', views.obtain_auth_token) ]
6.配置好后, 使用google浏览器的SERVISTATE插件来进行post测试
(之前没加X-CSRFTOKEN, 参考这个才弄成了 https://segmentfault.com/a/1190000016493704 和 https://segmentfault.com/a/1190000000764598 )
7.额外的, 可以发现, drf的authtoken在检查到用户发起请求时, 但用户如果没有token, 则会自动给用户生成token
第二节: 携带Token去访问
1. 有了前面的分析, 我们已经知道一个用户有一个Token, 而drf由于前后端分离的特性, 所以使用其自己的独特的token验证机制, 只要在访问的时候带上Token, 服务端就可以确定用户是谁, 接下来去验证一下
我们在ListModelMixin里面的queryset这里打断点, 并使用get发送一个请求
2. 从上面的结果来看, 对于普通请求, 服务端没有用户信息, 接下来去测试带上Token的值结果会是怎样
3. django是如何将user封装进来的,这个就需要对django的流程有所了解了, 转载 http://www.projectsedu.com/archives/ django从请求到返回都经历了什么
另外, REST是如何给用户生成Token的, 看下面的源码
urls中的views.obtain_auth_token.ObtainAuthToken ... def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, created = Token.objects.get_or_create(user=user) return Response({'token': token.key})
重点:
4. 现在有这么一种情况, 假设全局当中只有Goodslist接口是一个需要登陆后才能访问的接口, 那么我们前面的设置又是一个全局的Token检查, 怎么样才能达到对某一个接口实时单独的Token认证呢?
方法就是把Token认证移动到对应的View函数内部, 同时删掉全局Token认证
goods.view.py from rest_framework.authentication import TokenAuthentication class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): ... authentication_classes = [TokenAuthentication,] # 对goodslist接口单独设置Token认证 ...
----- 君子处其实,不处其华;治其内,不治其外 张居正 ------