首页 > 其他分享 >drf - jwt自定义表签发、jwt 多方式登录(auth的user表)

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

时间:2023-09-22 12:44:05浏览次数:78  
标签:username 自定义 jwt auth token user import password

jwt自定义表签发

1、导入模块:
	from rest_framework_jwt.settings import api_settings
2、写一个属性:
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
3、登录逻辑:
    class UserViews(ViewSet):
        @action(methods=["POST"], detail=False)
        def login(self, request, *args, **kwargs):
            username = request.data.get("username")
            password = request.data.get("password")
            user = User.objects.filter(username=username, password=password).first()
            print(user)
            if user:
                # 通过user生成payload----->jwt提供的方法,但是用户名的字段必须是username,传入user,生成payload
                payload = jwt_payload_handler(user)
                # 生成token ----->jwt提供了方法,把payload传入------>生成token
                token = jwt_encode_handler(payload)
                return Response({"code": 100, "msg": "登录成功", "username": user.username, "token": token})
            else:
                return Response({"code": 101, "msg": "登录失败,账号或密码输入错误"})

路由层

from django.urls import path, include
from app_one.views import UserViews
from rest_framework.routers import SimpleRouter

render = SimpleRouter()
render.register("users", UserViews, "users")

urlpatterns = [
    path('admin/', admin.site.urls),

    path('', include(render.urls)),
]

总结

基于自定义的用户表,签发token:
    -1、前端----->发起http请求,携带用户的用户名和密码----->到后端
    -2、后端从request.data中取出前端传入的数据----->字典格式------>取出用户名和密码
    -3、拿着用户名和密码去数据库中查询有没有该用户
    -4、如果有签发token
        -4.1、通过当前用户得到payload(自己生成荷载)
        -4.2、通过荷载生成token
    -5、返回给前端{"code":100,"msg":"登录成功","token":token,"username":user.username}
    -6、如果查不到该用户,返回用户名或密码输入错误

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

1、用户名+密码、邮箱+密码、手机号+密码  都可以登录
    username+password、email+password、phone+password
    无论是username,email,phone都以 username形式提交到后端
    于是:从username字段中取出来的,可能是用户名,可能是邮箱,可能是密码--->都能登录成功
2、auth的user签发
3、签发、校验用户逻辑------>放在序列化类中
4、存在一个问题--->已经迁移过表了--->已经存在auth的user表了,如果再去继承AbstractUser,再写用户表,就会出错
	-解决方案:以后尽量不要这么做
    	-以后要扩写auth的user表,一开始就要扩写,不要等迁移完之后再扩写
    -删库
    -删迁移文件(不要删__init__.py和migrations文件夹)
    	-项目app的迁移文件
        -django内置app的admin和auth的迁移文件
    
    -重新迁移--两条命令
    -扩写auth的user表,需要在配置文件配置 ###重要
5、创建超级用户----->创建到扩写的表中 auth的user-->AuthUser
	python  manage.py createsuperuser
面条版
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.decorators import action
from rest_framework_jwt.settings import api_settings
from rest_framework.response import Response
from .serializer import UserSerializer
from .models import AuthUser
import re
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class AuthUserView(GenericViewSet):
    serializer_class = UserSerializer

    @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).fister()

        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": user.username})
        else:
            return Response({"code": 101, "msg": "登录失败,账号或密码失败"})
封装版本:视图层
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.decorators import action
from rest_framework_jwt.settings import api_settings
from rest_framework.response import Response
from .serializer import UserSerializer
from .models import AuthUser

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

class AuthUserView(GenericViewSet):
    serializer_class = UserSerializer

    @action(methods=["POST"], detail=False)
    def login(self, request, *args, **kwargs):
        # 拿到前端传入的用户名和密码,得到一个序列化类对象
        user_serializer = self.get_serializer(data=request.data)
        if user_serializer.is_valid():
            token = user_serializer.context.get("token")
            username = user_serializer.context.get("username")
            return Response({"code": 100, "msg": "登录成功", "token": token, "username": username})
        else:
            return Response({"code": 101, "msg": "账号或密码输入错误"})
序列化类
from rest_framework import serializers
from .models import AuthUser
from rest_framework_jwt.settings import api_settings
from rest_framework.exceptions import AuthenticationFailed
import re

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class UserSerializer(serializers.ModelSerializer):
    # 需要重写字段,不重写,字段自己规则过不了
    username = serializers.CharField()

    class Meta:
        model = AuthUser
        fields = ["username", "password"]
        # username有字段自己的规则--->唯一 unique--->去数据库查询发现有lqz,之间字段自己规则报错了,不会走到全局钩子

    def _get_user(self, attrs):
        # 从校验的数据中取出username、password
        username = attrs.get("username")
        password = attrs.get("password")
        # 通过正则来匹配我的username是手机号还是邮箱还是用户名
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = AuthUser.objects.filter(phone=username).fister()

        elif re.match(r'^.+@.+$', username):
            user = AuthUser.objects.filter(email=username).first()

        else:
            user = AuthUser.objects.filter(username=username).first()
        # 如果我的用户对象以及我加密后的密码都为True,将这个user对象返回
        if user and user.check_password(password):
            return user
        # 否则主动抛出异常
        else:
            raise AuthenticationFailed("账号或密码输入错误")

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        # 如果返回user,说明,用户名密码对了,如果没走到这里,说明抛异常,抛异常说明用户名密码错误
        user = self._get_user(attrs)
        token = self._get_token(user)
        # 放在这里面  self 是序列化类的对象  ,context 是空字典,它是  视图类和序列化类之间沟通的桥梁
        self.context["username"] = user.username
        self.context["token"] = token
        return attrs

路由层
from django.contrib import admin
from django.urls import path, include
from app_one.views import AuthUserView
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register("user", AuthUserView, "user")

urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns += router.urls

总结

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

作业

# 1 自定义用户表,普通签发
# 2 扩写authuser表,多方式登录
# 3 自己的用户表,多方式登录

# -----自定义认证类-----

标签:username,自定义,jwt,auth,token,user,import,password
From: https://www.cnblogs.com/chao0308/p/17722057.html

相关文章

  • 自定义Kong网关提示信息
    vi/usr/local/share/lua/5.1/kong/runloop/handler.lua第1015行 修改自定义提示信息后请求一个不存在的路由 vi/usr/local/share/lua/5.1/kong/error_handlers.lua第67-80行 修改自定义提示信息后请求一个不存在的Upsream地址  ......
  • import引用自定义包、模块sys.path.append() ---转
    https://blog.csdn.net/Frank_LJiang/article/details/122656604import引用自定义包、模块)sys.path.append(问题sys.path.append()os.path.dirname(__file__)问题当引用不同文件下的自定义包时,容易出现以下问题ModuleNotFoundError:Nomodulenamed'ge'由于importxxx时,默认情......
  • Odoo 通过Javascript调用模型中自定义方法
    实践环境Odoo14.0-20221212(CommunityEdition)代码实现在js脚本函数中调用模型中自定义方法:this._rpc({model:'demo.wizard',//模型名称,即模型类定义中_name的值method:'action_select_records_via_checkbox',//模型中自定义名称args:['arg_value......
  • drf之jwt使用
    目录简介JWT构成JWT的使用安装快速使用定制返回格式jwt认证类简介Jsonwebtoken(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服......
  • docker存储路径修改到自定义目录路径
    通过修改Docker配置文件的方式来修改Docker数据存储路径,以减少系统盘的占用空间。具体步骤如下:1、停止Docker服务sudosystemctlstopdocker2、备份当前的Docker数据存储目录/var/lib/dockersudomv/var/lib/docker/var/lib/docker.bak3、创建新的Docker数据存......
  • 每日一题:vue3自定义指令大全(呕心沥血所作,附可运行项目源码)
    1.VUE常用指令大全本项目所有指令均为全局注册,使用时直接在组件中使用即可。指令目录:src/directives页面目录:src/views具体可查看源码1.1权限指令封装一个权限指令,在模板中根据用户权限来控制元素的显示或隐藏。permission.jsimport{ref,watchEffect}from'vue';c......
  • 自定义实现promise.all
    Promise.all是一个在JavaScript中常见的函数,用于处理一个Promise数组。当数组中的所有Promise都完成时,Promise.all将返回一个新的Promise,该Promise将解析为包含所有输入Promise解析值的数组。如果任何一个Promise失败,返回的Promise将立即被标记为失败,并且该数组将只包含失败的Prom......
  • VS2017使用自定义头文件
    VS2017使用自定义头文件头文件的使用能大大提高C语言编程效率。公共头文件直接使用类似于#include<stdio.h>即可。下面介绍如何使用自定义的头文件。实例:计算两个整数加和在源文件中添加Add.c源文件在头文件中,添加头文件myhead.h在主函数中,添加头文件声明没有......
  • 自定义初学2——扩展View
    倘若我们需要的功能找不到对应的系统控件了,这时我们就只能自己绘制了。首先定义一个继承View的基类,然后重写View类的一个或多个方法。通常可以被重写的方法有这些:onFinishInflate():这是一个回调方法,当应用从XML布局文件中加载组件时,该方法将被调用。onMeasure(int,int):该方法......
  • jwt配置及代码模板
    jwt配置及代码模板jwt工具类的使用依赖<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.6.0</version></dependency>application.properties配置jwt.config.key=userlogin......