首页 > 技术文章 > (生鲜项目)15. drf的用户认证 (解决django自带的csrf强制用户验证)

jiangzongyou 2019-12-26 18:18 原文

第一节: 基本介绍

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认证
    ...

 

 

 

 

 

 

 

 

 

 

 

-----  君子处其实,不处其华;治其内,不治其外   张居正 ------

推荐阅读