jwt自定义表签发、jwt 多方式登录(auth的user表)

补充

# 1 接口文档编写规范:-1 描述-2 请求地址-3 请求方式-4 请求参数-headers-请求体-请求参数-5 请求编码格式-6 返回格式-示例-返回数据字段含义-其他:-错误状态码-...-接口文档编写位置-写在文件中:word,md,跟前端共享-公司有接口文档平台-yapi-自研-第三方接口文档:coreapi,drf-yasg-自动生成---》访问项目地址 的 /doc 路径就能看到接口文档# 2 jwt-json  web token的缩写,web方向前后端认证的方式,传统的认证方案使用session,使用jwt后,服务端不需要再存数据了,数据都放在客户端-本质原理-jwt 分三段:-头:公司信息,加密方式,声明这是jwt-荷载:数据,用户信息,用户id,名字,邮箱,过期时间-签名:前面量部分通过某个加密方式加密得到一个签名,base64编码后拼接到最后-开发中:签发:登录,登录成功后,按照上面方式生成token串认证:客户端携带token到后端,使用原来的加密方式把第一段和第二段再做加密,加密后跟传入的第三代比较,如果一样,说明传入的token可靠,如果不一样,说明数据被篡改,伪造的,不能信任,程序不能继续往后走了----------------------------------------------------------------------------------        
# 3 base64-加密算法-1 编码和解码,不加密:base64,url编码和解码-2 摘要算法:md5,sha1   不能解开-3 对称加密:des,AES     能加密,能解密;加密和解密使用同样的秘钥-4 非对称加密 :RSA  能加密,能解密,加密秘钥和解密秘钥是不同的:公钥和私钥-编码和解码使用内置模块
----------------------------------------------------------------------------------    # 4 django使用jwt-django-rest-framework-jwt:有点老-djangorestframework-simplejwt:新的# 5 快速使用-签发:path('login/', obtain_jwt_token),-认证(局部使用,全局使用,局部禁用):authentication_classes = [JSONWebTokenAuthentication,]permission_classes = [IsAuthenticated]

1 jwt自定义表签发

1.1 models.py

from django.db import modelsfrom django.contrib.auth.models import AbstractUser# 继承AbstractUser 直接使用自动签发token# 纯自己写的用户表,需要自己签发
class User(models.Model):username = models.CharField(max_length=32)password = models.CharField(max_length=32)email = models.EmailField(max_length=32)gender = models.IntegerField(choices=((1, '男'), (2, '女'), (0, '未知')))

1.2 视图

from django.shortcuts import renderfrom rest_framework.views import APIView
from .models import User
from rest_framework.response import Responsefrom rest_framework_jwt.settings import api_settings  # drf的配置文件# from rest_framework_jwt.utils import jwt_payload_handler
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# rest_framework_jwt.utils.jwt_encode_handler
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLERclass UserView(APIView):def post(self, request):username = request.data.get('username')password = request.data.get('password')user = User.objects.filter(username=username, password=password).first()if user:# 签发token# 1 通过user生成payload---》jwt 提供一个方法(username),传入user,返回payload# payload = jwt_payload_handler(user)payload={'username':'asdfasdf','exp':1694401763}# 2 生成token---》jwt提供了方法,把payload放入--》tokentoken = jwt_encode_handler(payload)return Response({'code': 101, 'msg': '登录成功', 'token': token, 'username': user.username})else:return Response({'code': 101, 'msg': '用户名或密码错误'})

1.3 路由

path('login/', UserView.as_view()),

2 jwt 多方式登录(auth的user表)

#1 用户名+密码   邮箱+密码  手机号+密码  都可以登录username+passwordemail+passwordphone+password无论是username,email,phone都以 username形式提交到后端于是:从username字段中取出来的,可能是用户名,可能是邮箱,可能是密码---》都能登录成功
#2  auth的user签发
#3  签发,校验用户 逻辑-----》放在序列化类中# 5 存在一个问题---》已经迁移过表了---》已经存在auth的user表了,如果再去继承AbstractUser,再写用户表,就会出错-解决方案:以后尽量不要这么做-以后要扩写auth的user表,一开始就要扩写,不要等迁移完之后再扩写-删库-删迁移文件(不要删__init__.py和migrations文件夹)-项目app的迁移文件-django内置app的admin和auth的迁移文件-重新迁移--两条命令-扩写auth的user表,需要在配置文件配置 ###重要# 6 创建超级用户--->创建到扩写的表  auth的user--》AuthUserpython  manage.py createsuperuser

在这里插入图片描述

2.1 总结流程

# 序列化,反序列化,数据校验---》只用来做数据校验
# 前端传过来的字段,都要,而且要校验 :username  password
# 只要视图类中执行 ser.is_valid():会走字段自己的规则---》username过不了---》因为有unique---》所有需要重写会走局部钩子---》这里没写会走全局钩子---》全局钩子里校验-分成了两个方法:好处是以后修改方法-_get_user :多方式的 ,以后改成单方式登录,只要该这个方法即可 -_get_token:用的第三方签发,后期改成自己的签发,只需要改它即可-把生成的token和用户名放到了,序列化类中,单是怕污染数据,放到了序列化类的对象的context中# 视图类中取出token和usernametoken = ser.context.get('token')username = ser.context.get('username')

2.2 序列化类

from .models import AuthUser
from rest_framework import serializers
import re
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.settings import api_settings  # drf的配置文件# from rest_framework_jwt.utils import jwt_payload_handler
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# rest_framework_jwt.utils.jwt_encode_handler
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER# 序列化类干什么? 只用来反序列化的校验
class LoginSerializer(serializers.ModelSerializer):# username 是表中的字段---》自动映射过来的-->A user with that username already exists# username有字段自己的规则---》唯一 unique---》去数据库查询发现有lqz,之间字段自己规则报错了,不会走到全局钩子username=serializers.CharField() # 需要重写字段,不重写,字段自己规则过不了class Meta:model = AuthUser  # 千万不要加逗号,程序运行不会报错,使用这个地方的时候,就报错了fields = ['username', 'password']# 在类内部  用 __ 开头表示隐藏# 我们约定俗称,以 _ 开头的,表示只在类内部使用,不给外部用,但是万一外部要用,之间用既可以了def _get_user(self, attrs):# 用户名从哪拿? attrs是前端传入,校验过后的数据  {"username": "lqz","password": "lqz12345" }username = attrs.get('username')password = attrs.get('password')if re.match(r'^1[3-9][0-9]{9}$', username):  # 说明,用户提交的是手机号+密码user = AuthUser.objects.filter(phone=username).first()elif re.match(r'^.+@.+$', username):  # (这个邮箱正则,不太准确) 如果是邮箱,说明用户提交的是  邮箱+密码user = AuthUser.objects.filter(email=username).first()else:user = AuthUser.objects.filter(username=username).first()if user and user.check_password(password):return userelse:# 在全局钩子中,只要校验不通过,就抛异常# 不是returnraise ValidationError('用户名或密码错误')def _get_token(self, user):payload = jwt_payload_handler(user)token = jwt_encode_handler(payload)return tokendef validate(self, attrs):# 1 校验用户user = self._get_user(attrs)  # 如果返回user,说明,用户名密码对了,如果没走到这里,说明抛异常,抛异常说明用户名密码错误# 2签发tokentoken = self._get_token(user)# 3 放在这里面  self 是序列化类的对象  ,context 是空字典,它是  视图类和序列化类之间沟通的桥梁self.context['token'] = tokenself.context['username'] = user.username# 4 返回校验过后的数据return attrs

2.3 视图类

## 2.基于auth的user表签发token,做多种方式登录
'''用户名+密码   邮箱+密码  手机号+密码  都可以登录username+passwordemail+passwordphone+password无论是username,email,phone都以 username形式提交到后端于是:从username字段中取出来的,可能是用户名,可能是邮箱,可能是密码---》都能登录成功
'''
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.decorators import action
import refrom .serializer import LoginSerializer
from .models import AuthUserclass UserView(GenericViewSet):# 不需要做序列化或者反序列化,则可以不用写queryset# queryset =serializer_class = LoginSerializer@action(methods=['POST'], detail=False)def login(self, request, *args, **kwargs):username = request.data.get('username')password = request.data.get('password')# 正则匹配,如果是手机号,要查手机号+密码;如果是邮箱,要查邮箱+密码;如果是其他,则查用户+密码if re.match(r'^1[3-9][0-9]{9}$', username):user = AuthUser.objects.filter(phone=username).first()elif re.match(r'^.+@.+$', username):user = AuthUser.objects.filter(email=username).first()else:user = AuthUser.objects.filter(username=username).first()if user and user.check_password(password):# 签发payload = jwt_payload_handler(user)token = jwt_encode_handler(payload)return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': username})return Response({'code': 101, 'msg': '用户名或密码错误'})-------------------优化版----------------------------------------------------
from rest_framework_jwt.views import obtain_jwt_token
## 复杂方式---》校验逻辑--》放在序列化类中
class UserView(GenericViewSet):# queryset = 可以不写serializer_class = LoginSerializer@action(methods=['POST'], detail=False)def login(self, request, *args, **kwargs):# 拿到前端传入的用户名和密码,得到一个序列化类对象ser = self.get_serializer(data=request.data)if ser.is_valid():  # 字段自己(校验不过,因为username在数据库中有你传入的这个名字了),局部钩子,全局钩子---》需要在序列化类中写# 校验完,并且签发完token了# token从 序列化类的对象 取出来# username从   序列化类的对象 取出来# 现在不明白如何取出来的,假设取出来是对的---》因为在全局钩子中放入到了context中token = ser.context.get('token')username = ser.context.get('username')return Response({'code': 100, 'msg': '登录成功', 'token': token, 'username': username})else:return Response({'code': 101, 'msg':'用户名密码错误'})

2.4 路由

from django.contrib import admin
from django.urls import path
from app01.views import UserView
from rest_framework.routers import SimpleRouterrouter = SimpleRouter()
router.register('user', UserView, 'user') # 127.0.0.1:8000/user/login  的post请求
urlpatterns = [path('admin/', admin.site.urls),# path('login/', UserView.as_view()),
]
urlpatterns += router.urls

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/76348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos定期清理磁盘

centos/linux定期清理磁盘 要定时清理空间,我们需要了解一个命令,find 命令,这个命令可以查询目录下特定文件名,生成日期的文件 小白教程,一看就会,一做就成。 1.查找需要删除的 find /data_back/zhhyba…

自动计算比例 计算属性 computed @input=“rate“

<el-col :span"12"><el-form-item label"当年累计实收租金:" prop"cumulativeRent"><el-inputv-model"createForm.cumulativeRent"input"rate"clearable:disabled"value 2"><template slot…

2023-9-11 拆分-Nim游戏

题目链接&#xff1a;拆分-Nim游戏 #include <iostream> #include <cstring> #include <algorithm> #include <unordered_set>using namespace std;const int N 110;int f[N];int sg(int x) {if(f[x] ! -1) return f[x];unordered_set<int> S;f…

图片码二次渲染绕过

目录 一、环境 1、代码 2、文件处理方式 3、图片码的制作 二、绕过图片重构 1、可行性分析 2、数据比对 3、完成绕过 一、环境 以upload-labs靶场第十七关为例 1、代码 源码为&#xff1a; <?php include ../config.php; include ../head.php; include ../menu.…

Docker安装部署Nexus3作为内网镜像代理缓存容器镜像

Docker安装部署Nexus3作为内网镜像代理 一、背景描述 基础镜像比较小&#xff0c;仓库使用阿里云或者腾讯云拉取速度挺快&#xff0c;但是时光飞逝几年时间过去&#xff0c;再加上AI加持的情况下&#xff0c;有些镜像的大小已经接近20G&#xff01; 这种情况下不管是测试环境…

2024年java面试--mysql(2)

系列文章目录 2024年java面试&#xff08;一&#xff09;–spring篇2024年java面试&#xff08;二&#xff09;–spring篇2024年java面试&#xff08;三&#xff09;–spring篇2024年java面试&#xff08;四&#xff09;–spring篇2024年java面试–集合篇2024年java面试–redi…

网络传输方式

1. 单播 1.1. 定义 单播是指一种向单个目标地址传送数据的方式&#xff0c;即单独的一对一通讯方式。 1.2. 可使用协议 UDP、TCP等协议 1.3. 常见的场景 发送电子邮件传输文件 2. 广播 2.1. 定义 一种向本地网络中所有设备发送数据的方式。 2.2. 常见的场景 电视和电…

功率放大器的定义详解

功率放大器是一种电子放大器&#xff0c;主要用于将输入信号的功率放大到足以驱动负载或输出器件所需的水平。通常&#xff0c;功率放大器会将低电平高电流的输入信号转换成高电平低电流的输出信号&#xff0c;以便给负载提供足够的功率。 功率放大器广泛应用于各种应用场合&am…

Linux工具——gcc

目录 一&#xff0c;gcc简介 二&#xff0c;C语言源文件的编译过程 1.预处理 2.编译 3.汇编 4.链接 5.动静态库 一&#xff0c;gcc简介 相信有不少的小白和我一样在学习Linux之前只听说过visual studio。其实这个gcc这个编译器实现的功能便是和visual studio一样的功能&…

学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《推荐】Spring与Mybatis集成整合》 ⛺️ 生活的理想&#xff0c;不断更新自己 ! 1.JSR303 1.1JSR303是什么 JSR 303是Java规范请求&#xff08;Java Specification Request&#xff09;…

matlab数据处理: cell table array+datetime

原数据文件.csv matlab xlsread(filename{i},B2:T2881) 会同于Excel最多1048576行 舍弃 a{1,i} xlsread(filename{i},‘B2:T2881’);%读取excel文件,选定区域’B2:G2881’ readcell(filename{i},Range,E2:M2881) 会全部读取 优选 对于日期 yyyy-MM-dd HH:mm:ss.000 matlab cel…

在Ubuntu上建立博客网站,利用Cpolar+Inis快速实现专业写作

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

将 ChatGPT 用于数据科学项目的指南

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 我们都知道 ChatGPT 的受欢迎程度以及人们如何使用它来提高生产力。但是&#xff0c;如果您是新手&#xff0c;则值得注册ChatGPT免费演示并尝试它所能做的一切。您还应该参加我们的 ChatGPT 简介课程&#xff0c;学习…

Mixin从理论到实践

mixin从理论到实践 mixin从理论到实践一、什么是mixin二、使用mixin三、mixin的合并策略四、mixin辨析五、个人实践 mixin从理论到实践 一、什么是mixin mixin混入 — Vue.js (vuejs.org) 官方解释&#xff1a; 混入 (mixin) 提供了一种非常灵活的方式&#xff0c;来分发 Vue …

产品波士顿矩阵

随着公司产品的增多&#xff0c;每个产品的生命周期节点各不相同&#xff0c;很多时候我们往往在产品结构、资源分配方面会产生各种问题&#xff0c;导致需要发展的产品得不到资源&#xff0c;消耗资源的产品却有无法增长&#xff0c;所谓不聚焦导致的问题其实是资源和发展错配…

在阿里云 linux 服务器上查看当前服务器的Nginx配置信息

我们可以通过命令 sudo nginx -t查看到nginx.conf的路径 可以通过 sudo nginx -T查看 nginx 详细配置信息&#xff0c;包括加载的配置文件和配置块的内容 其中也会包括配置文件的内容

环境扫描/透射电子显微镜气体样品架的真空压力和微小流量控制解决方案

摘要&#xff1a;针对环境扫描/透射电子显微镜对样品杆中的真空压力气氛环境和流体流量精密控制控制要求&#xff0c;本文提出了更简单高效和准确的国产化解决方案。解决方案的关键是采用动态平衡法控制真空压力&#xff0c;真空压力控制范围为1E-03Pa~0.7MPa&#xff1b;采用压…

git 合并分支某次(commit)提交

需求&#xff1a;将develop分支某次提交合并到master上面&#xff0c;其他修改不同步&#xff1b; //切换到master分支 git checkout master //查看develop分支提交记录&#xff0c;获取对应记录哈希值&#xff1b; git log develop // 按上下按钮可以上下查询对应记录&#xf…

DevOps到底是什么意思?

前言: 当我们谈到 DevOps 时,可能讨论的是:流程和管理,运维和自动化,架构和服务,以及文化和组织等等概念。那么,到底什么是"DevOps"呢? 那么,DevOps是什么呢? 有人说它是一种方法,也有人说它是一种工具,还有人说它是一种思想。更有甚者,说它是一种哲学…

读高性能MySQL(第4版)笔记06_优化数据类型(上)

1. 良好的逻辑设计和物理设计是高性能的基石 1.1. 反范式的schema可以加速某些类型的查询&#xff0c;但同时可能减慢其他类型的查询 1.2. 添加计数器和汇总表是一个优化查询的好方法&#xff0c;但它们的维护成本可能很 1.3. 将修改schema作为一个常见事件来规划 2. 让事情…