您现在的位置是: 网站首页 >Django >Vue+Django REST framework前后端分离生鲜电商 Django

【Vue+DRF生鲜电商】12.用户登录之DRF Token认证登录原理和使用方法

admin2019年5月4日 21:56 Django | Python | Vue 1886人已围观

Vue+Django REST framework前后端分离生鲜电商简介 Vue+Django REST framework 打造前后端分离的生鲜电商项目(慕课网视频)。 Github地址:https://github.com/xyliurui/DjangoOnlineFreshSupermarket ; Django版本:2.2、djangorestframework:3.9.2。 前端Vue模板可以直接联系我拿。

在购买商品时,需要用户登录才能操作,所以就必须要增加登录和注册功能。 由于在Django中配置了`path('api-auth/', include('rest_framework.urls')), # drf 认证url`的URL,所以在DRF中可以直接使用认证功能 比如退出登录后,此时的链接为: http://127.0.0.1:8000/api-auth/login/?next=/goods/ ![BLOG_20190504_220135_67](/media/blog/images/2019/05/BLOG_20190504_220135_67.png "博客图集BLOG_20190504_220135_67.png") 在这也有csrf做表单的安全验证。但是在前后端分离的系统中是无法使用的。 前端会运行到其他站点,相当于是跨站了,无法使用csrf验证。 ## DRF Token认证登陆原理 访问 https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication 查看使用方法 此身份验证方案使用一个简单的基于令牌的HTTP身份验证方案。令牌身份验证适用于客户机-服务器设置,例如本机桌面和移动客户机。 要使用`TokenAuthentication`方案,需要将身份验证类配置为包含`TokenAuthentication`,另外还包括`rest_framework.authtoken`在`INSTALLED_APPS`设置中。 https://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme 中介绍到:可以使用`DEFAULT_AUTHENTICATION_CLASSES`设置全局设置缺省身份验证方案。也就是默认为: ```python # 文章示例 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ) } ``` 要使用`TokenAuthentication`认证们还需要增加`'rest_framework.authentication.SessionAuthentication',` ### 配置全局TokenAuthentication 在这个项目中配置为: ```python # DRF配置 REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # 'PAGE_SIZE': 5, 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', # 上面两个用于DRF基本验证 'rest_framework.authentication.TokenAuthentication', # TokenAuthentication ) } ``` 然后添加`rest_framework.authtoken`到APPS ```python INSTALLED_APPS = [ # 'simpleui', # 第三方后台,使用https://github.com/newpanjing/simpleui 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 添加drf应用 'rest_framework', 'rest_framework.authtoken', 'django_filters', # Django跨域解决 'corsheaders', # 注册富文本编辑器ckeditor 'ckeditor', # 注册富文本上传图片ckeditor_uploader 'ckeditor_uploader', 'users.apps.UsersConfig', 'goods.apps.GoodsConfig', 'trade.apps.TradeConfig', 'user_operation.apps.UserOperationConfig', ] ``` 配置完成后执行数据库迁移 ```bash manage.py@DjangoOnlineFreshSupermarket > makemigrations manage.py@DjangoOnlineFreshSupermarket > migrate ``` 执行完查看数据库会增加一个`authtoken_token`的表 ![BLOG_20190504_220109_13](/media/blog/images/2019/05/BLOG_20190504_220109_13.png "博客图集BLOG_20190504_220109_13.png") `user_id`是一个外键,指向现有的用户表。如果之前已经创建了用户,在这个token表是没有记录的。这个表和用户表是一一对应的。创建用户表后需要手动创建token表。也就是当用户注册时,需要调用`token = Token.objects.create(user=...)`来生成token。 对于要进行身份验证的客户机,令牌密钥应该包含在授权HTTP头中。键应该以字符串文字“Token”作为前缀,并用空格分隔两个字符串。例如:`Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b` ### 添加api-token-auth URL 在使用`TokenAuthentication`时,可能希望为客户端提供一种机制,以获得给定用户名和密码的令牌。REST框架提供了一个内置视图来提供这种行为。要使用它,请将`obtain_auth_token`视图添加到您的URLconf: ```python from rest_framework.authtoken import views urlpatterns = [ path('admin/', admin.site.urls), path('api-auth/', include('rest_framework.urls')), # drf 认证url path('api-token-auth/', views.obtain_auth_token), # drf token获取的url path('ckeditor/', include('ckeditor_uploader.urls')), # 配置富文本编辑器url path('', include(router.urls)), # API url现在由路由器自动确定。 # DRF文档 path('docs/', include_docs_urls(title='DRF文档')), ] ``` ### 测试获取token的API 当使用表单数据或JSON将有效的用户名和密码字段提交到视图时,`obtain_auth_token`视图将返回一个JSON响应,测试如下: 这儿使用了一个Google浏览器插件**Restlet Client - REST API Testing ** ![BLOG_20190504_220050_22](/media/blog/images/2019/05/BLOG_20190504_220050_22.png "博客图集BLOG_20190504_220050_22.png") ![BLOG_20190504_220031_76](/media/blog/images/2019/05/BLOG_20190504_220031_76.png "博客图集BLOG_20190504_220031_76.png") 向 http://127.0.0.1:8000/api-token-auth/ 接口 POST `username`和`password` ![BLOG_20190504_220012_22](/media/blog/images/2019/05/BLOG_20190504_220012_22.png "博客图集BLOG_20190504_220012_22.png") 然后这个接口就返回一个token,这时候刷新数据库,就可以看到数据库中已经创建该用户关联的key ![BLOG_20190504_220003_47](/media/blog/images/2019/05/BLOG_20190504_220003_47.png "博客图集BLOG_20190504_220003_47.png") 拿到这个key后,对于要进行身份验证的客户机,令牌密钥应该包含在授权HTTP头中。键应该以字符串文字“Token”作为前缀,并用空格分隔两个字符串。例如: ``` Authorization: Token ff2634eac32ffa4a057ef1f864e738c9e17890e0 ``` ### 使用token进行访问 然后将其填入到请求header中,用来请求所有商品: http://127.0.0.1:8000/goods/ 怎么查看是否是通过认证的用户呢 ![BLOG_20190504_215854_51](/media/blog/images/2019/05/BLOG_20190504_215854_51.png "博客图集BLOG_20190504_215854_51.png") 由于以下视图不好打断点 ```python class GoodsListView(generics.ListAPIView): """ 显示所有的商品列表 """ queryset = Goods.objects.all() serializer_class = GoodsSerializer pagination_class = GoodsPagination ``` 就在`mixins.ListModelMixin`中打上断点。 ![BLOG_20190504_215845_56](/media/blog/images/2019/05/BLOG_20190504_215845_56.png "博客图集BLOG_20190504_215845_56.png") 就可以看到已经可以取出user的值了。 通过以上配置后,数据表中的`token`是永久有效的,它没有被设置过期时间,只要其他人拿到了这个`token`的值,那么就可以用这个`token`来访问网站,实质上是极不安全的。 ## viewsets配置DRF Token认证类 由于已经在 settings.py 中配置了全局token认证:`'rest_framework.authentication.TokenAuthentication'`,对token进行认证,如果验证失败,就会产生异常。 测试,如果传入了一个错误的token,然后去请求: http://127.0.0.1:8000/goods/ 那么,他就会产生错误 ![BLOG_20190504_215814_96](/media/blog/images/2019/05/BLOG_20190504_215814_96.png "博客图集BLOG_20190504_215814_96.png") 但是,商品列表页这种公开的数据,用户不登陆或者登录错误的情况下都应该是可以访问的。另外用户`token`可能会过期的,这时候来访问一个公共的数据也会产生401错误。访问公共数据可以不带`token`,但是很多前端在写的时候都是全局带`token`的。如果在后端解决这个问题? ### 取消全局TokenAuthentication 就需要在 settings.py 中全局`TokenAuthentication`放在视图中处理,那么 settings.py 就需要进行修改,注释掉`TokenAuthentication` ```python # DRF配置 REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # 'PAGE_SIZE': 5, 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', # 上面两个用于DRF基本验证 # 'rest_framework.authentication.TokenAuthentication', # TokenAuthentication,取消全局token,放在视图中进行 ) } ``` ### 视图中添加TokenAuthentication 在`GoodsListViewSet`视图中进行测试,添加`authentication_classes` ```python from rest_framework.authentication import TokenAuthentication class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ 显示商品列表,分页、过滤、搜索、排序 """ queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值 serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,) # 将过滤器后端添加到单个视图或视图集 filterset_class = GoodsFilter authentication_classes = (TokenAuthentication, ) # 只在本视图中验证Token search_fields = ('name', 'goods_desc', 'category__name') # 搜索字段 ordering_fields = ('click_num', 'sold_num', 'shop_price') # 排序 ``` 调试看下能否在继承成类`mixins.ListModelMixin`---`ListModelMixin`---`list`函数中获取到`token`,添加断点 使用正确的`token`请求 http://127.0.0.1:8000/goods/ ![BLOG_20190504_215802_47](/media/blog/images/2019/05/BLOG_20190504_215802_47.png "博客图集BLOG_20190504_215802_47.png") 可以在调试结果中获取到`user`和`token`的值 ![BLOG_20190504_215746_23](/media/blog/images/2019/05/BLOG_20190504_215746_23.png "博客图集BLOG_20190504_215746_23.png") 如果取消视图中的`authentication_classes`类 ```python class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ 显示商品列表,分页、过滤、搜索、排序 """ queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值 serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,) # 将过滤器后端添加到单个视图或视图集 filterset_class = GoodsFilter # authentication_classes = (TokenAuthentication, ) # 只在本视图中验证Token search_fields = ('name', 'goods_desc', 'category__name') # 搜索字段 ordering_fields = ('click_num', 'sold_num', 'shop_price') # 排序 ``` 再来做同样的请求,就获取不到`user`的值了 ![BLOG_20190504_215734_16](/media/blog/images/2019/05/BLOG_20190504_215734_16.png "博客图集BLOG_20190504_215734_16.png")

很赞哦! (1)

文章交流

  • emoji
0人参与,0条评论

当前用户

未登录,点击   登录

站点信息

  • 建站时间:网站已运行1163天
  • 系统信息:Linux
  • 后台程序:Python: 3.8.10
  • 网站框架:Django: 3.2.6
  • 文章统计:256 篇
  • 文章评论:54 条
  • 腾讯分析网站概况-腾讯分析
  • 百度统计网站概况-百度统计
  • 公众号:微信扫描二维码,关注我们
  • QQ群:QQ加群,下载网站的学习源码
返回
顶部
标题 换行 登录
网站