Django+Vue开发生鲜电商平台之7.用户登录和注册功能(上)

简介: 基于DRF的前后端分离登录与单独使用Django登录的原理不同,不再需要CSRF验证,DRF提供了许多开箱即用的身份验证方案,并且还允许实现自定义方案。

一、DRF的token基本使用

1.DRF的token登录原理

基于DRF的前后端分离登录与单独使用Django登录的原理不同,不再需要CSRF验证,DRF提供了许多开箱即用的身份验证方案,并且还允许实现自定义方案。身份验证始终在视图的最开始处,在进行权限和限制检查之前以及在允许任何其他代码进行之前运行。

身份验证方案始终定义为类列表,DRF框架尝试对列表中的每个类进行身份验证,并使用成功进行身份验证的第一个类的返回值设置request.user和request.auth。

在使用前,需要在settings.py中进行配置:

# DRF配置
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ]
}

DRF提供4种认证类,包括BasicAuthentication、TokenAuthentication、SessionAuthentication和RemoteUserAuthentication:

BasicAuthentication机制使用HTTP基本身份验证,该身份针对用户的用户名和密码进行了签名,在实际开发中一般仅适用于测试;

TokenAuthentication身份验证方案使用基于令牌的简单HTTP身份验证方案,适用于客户端-服务器设置,例如本地台式机和移动客户端,适用于前后端分离项目,也是本项目中身份验证的重点;

SessionAuthentication机制常见于浏览器,因为浏览器可以自动设置cookie,并将session和cookie传到浏览器,在后端分离项目中较少见;

对于RemoteUserAuthentication,通过此身份验证方案,可以将身份验证委派给Web服务器,要求服务器设置REMOTE_USER环境变量。

综上,选择TokenAuthentication,即选择Token的认证方式,需要在settings.py中添加到INSTALLED_APPS:

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apps.users.apps.UsersConfig',
    'goods.apps.GoodsConfig',
    'trade.apps.TradeConfig',
    'user_operation.apps.UserOperationConfig',
    'DjangoUeditor',
    'xadmin',
    'crispy_forms',
    'django.contrib.admin',
    'rest_framework',
    'django_filters',
    'corsheaders',
    'rest_framework.authtoken'
]

加入之后,执行makemigrationsmigrate命令进行数据映射,查看数据库可以看到生成新表authtoken_token,其表结构如下:

+---------+-------------+------+-----+---------+-------+ 
| Field   | Type        | Null | Key | Default | Extra | 
+---------+-------------+------+-----+---------+-------+ 
| key     | varchar(40) | NO   | PRI | NULL    |       | 
| created | datetime(6) | NO   |     | NULL    |       | 
| user_id | int(11)     | NO   | UNI | NULL    |       | 
+---------+-------------+------+-----+---------+-------+ 
3 rows in set (0.01 sec)                                 

其中,user_id是一个外键,指向users_userprofile表,表中的key(即token)和user之间具有一对一的关系。

但是在创建用户后并不会自动创建token,而是需要自己创建,可以使用HTTP请求模拟发送工具进行发送参数创建,使用Postman演示如下:

2345_image_file_copy_29.jpg

显然,通过携带数据访问http://127.0.0.1:8000/api-token-auth/,生成了当前用户的token并获取到,在生成token的同时,自动将生成的token和当前用户存入表authtoken_token中,如下:

+------------------------------------------+----------------------------+---------+
| key                                      | created                    | user_id |
+------------------------------------------+----------------------------+---------+
| 236de0331b3e5a89665771f9aaff9be720cbba04 | 2020-07-27 08:29:47.306382 |       1 |
+------------------------------------------+----------------------------+---------+
1 row in set (0.01 sec)

现在已经获取到了token,就可以使用了。为了使客户端进行身份验证,令牌密钥应包含在Authorization HTTP标头中。密钥应以字符串文字Token作为前缀,并用空格分隔两个字符串。

此时再使用获取到的Token请求商品数据如下:

image.jpeg

显然,获取到了商品数据,可以体会到token比session的应用更方便,但是使用token验证也存在一些问题:

请求服务器生成的token只存在于一台被请求的服务器中,如果是分布式系统,为了数据一致,则需要将该服务器的数据同步到其他服务器,增加了操作和维护难度;

token没有过期时间,显然这对于验证来说并不完善。

2.viewsets设置认证类

在使用token认证时,如果token不正确,则会抛出异常,并且如果对于本来不需要认证即可访问的公开数据要是再需要正确的token才能访问的话,就会降低项目的友好性,此时可以对token不采用全局设置,而在View中单独设置,settings.py如下:

# DRF配置
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ]
}

为了测试,在apps/goods/views.py中进行配置如下:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    '''商品列表页,并实现分页、搜索、过滤、排序'''
    queryset = Goods.objects.filter(is_delete=False)
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    authentication_classes = [TokenAuthentication]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filter_class = GoodsFilter
    search_fields = ['name', 'goods_brief', 'goods_desc']
    ordering_fields = ['sold_num', 'shop_price']

此时再请求http://127.0.0.1:8000/goods/,request.user即为当前用户admin。

当然在实际项目中由于goods是公开数据,因此不需要设置authentication_classes配置验证,还是为:

class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    '''商品列表页,并实现分页、搜索、过滤、排序'''
    queryset = Goods.objects.filter(is_delete=False)
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filter_class = GoodsFilter
    search_fields = ['name', 'goods_brief', 'goods_desc']
    ordering_fields = ['sold_num', 'shop_price']

二、JSON Web Token登录

1.JWT原理

JSON Web Token (简称JWT),是目前最流行的跨域身份验证解决方案,使用基于Token的身份验证方法,在服务端不需要存储用户的登录记录。

在之前已经测试过,传统的前后端分离项目中,前端登录,后端生成对应的token信息并保存到session或数据库中。但是如果存在XSS漏洞,就可能存在cookie泄漏、信息不安全的问题。如果将验证信息保存到数据库中,会增加数据库的操作和存储开销;如果存到session中,又会增大服务器存储压力;如果采用加密算法来对用户信息加密得到token,则很容易被解密而泄漏用户信息。

JWT是一种开放的、行业标准的RFC7519方法,用于在双方之间安全地表示声明,JWT是凭据,使用加密算法加密,可以授予对资源的访问权限,具有简洁、自包含的特点。

JWT消息组成包含三部分:

Header头部

包含token类型和加密算法,并使用base64编码。

Payload负载

存放信息,包含用户id、签发者、面向的用户、接收方、签发时间和过期时间等,也通过base编码。

Signature签名

因为Header和Payload信息可以通过解码获取到具体信息并伪造信息进行请求,因此需要通过签名来进行识别,其使用Header中指定的算法对Header和Payload信息以及提供的密钥进行签名,来保证安全性。

相比于session,JWT将登录信息保存到本地,减轻了服务器的存储压力,并且可应用于单点登录。

2.使用JWT完成用户认证

在DRF中使用JWT需要先安装依赖库,直接在虚拟环境中使用命令pip install djangorestframework-jwt安装即可。

安装后,需要在settings.py中进行配置:

# DRF配置
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ]
}

JSONWebTokenAuthentication可以对用户发送来的数据Token进行验证,并取出其中的user。

还需要在users.py中配置路由:

from django.conf.urls import url, include
from django.views.static import serve
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken import views
from rest_framework_jwt.views import obtain_jwt_token
import xadmin
from .settings import MEDIA_ROOT
from goods.views import GoodsListViewSet, CategoryViewSet
# Create a router and register our viewsets with it.
router = DefaultRouter()
# 配置goods的路由
router.register(r'goods', GoodsListViewSet, basename='goods')
# 配置categories的路由
router.register(r'categorys', CategoryViewSet, basename='categorys')
urlpatterns = [
       url(r'^xadmin/', xadmin.site.urls),
       url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}),
       url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
       # 商品列表页
       url(r'^', include(router.urls)),
       # 文档路由
       url(r'docs/', include_docs_urls(title='生鲜电商')),
       # DRF自带认证路由
       url(r'^api-token-auth/', views.obtain_auth_token, name='api_token_auth'),
       # JWT认证路由
       url(r'^jwt-auth/', obtain_jwt_token),
]

现对JWT进行获取和验证测试如下:

image.jpeg

显然获取到了JWT,并且可以正常作为用户信息进行登录访问。

相关文章
|
7天前
|
JavaScript 前端开发
【Vue.js】监听器功能(EventListener)的实际应用【合集】
而此次问题的核心就在于,Vue实例化的时机过早,在其所依赖的DOM结构尚未完整构建完成时就已启动挂载流程,从而导致无法找到对应的DOM元素,最终致使计算器功能出现异常,输出框错误地显示“{{current}}”,并且按钮的交互功能也完全丧失响应。为了让代码结构更为清晰,便于后续的维护与管理工作,我打算把HTML文件中标签内的JavaScript代码迁移到外部的JS文件里,随后在HTML文件中对其进行引用。
28 8
|
2月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
225 45
|
2月前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能
|
2月前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
3月前
|
IDE 关系型数据库 MySQL
Django学习一:创建Django框架,介绍Django的项目结构和开发逻辑。创建应用,编写主包和应用中的helloworld
这篇文章是关于如何创建一个Django框架,介绍Django的项目结构和开发逻辑,并指导如何创建应用和编写“Hello, World!”程序的教程。
207 3
Django学习一:创建Django框架,介绍Django的项目结构和开发逻辑。创建应用,编写主包和应用中的helloworld
|
2月前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
83 2
|
JavaScript 网络架构 Python
|
4月前
|
机器学习/深度学习 人工智能 算法
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
植物病害识别系统。本系统使用Python作为主要编程语言,通过收集水稻常见的四种叶片病害图片('细菌性叶枯病', '稻瘟病', '褐斑病', '稻瘟条纹病毒病')作为后面模型训练用到的数据集。然后使用TensorFlow搭建卷积神经网络算法模型,并进行多轮迭代训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地模型文件。再使用Django搭建Web网页平台操作界面,实现用户上传一张测试图片识别其名称。
162 22
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
|
2月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
55 1
|
3月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
59 4

热门文章

最新文章