FastAPI(六十七)实战开发《在线课程学习系统》接口开发--用户登陆接口开发

news2024/11/14 2:51:36

 源码见:"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统"

接上一篇文章FastAPI(六十六)实战开发《在线课程学习系统》接口开发--用户注册接口开发。这次我们分享实际开发--用户登陆接口开发。

我们先来梳理下逻辑:

1.查询用户是否存在

2.校验密码是否正确

3.密码校验失败记录失败次数

4.60分钟内失败次数大于等于3次,60分钟内不能登陆

5.密码校验通过产生对应的token返回

接着我们去设置pydantic登录参数校验模型,同样添加到user_schemas.py中

class UserLogin(UserBase):
    """登录校验模型"""
    password: str = Field(min_length=8, max_length=16)

这里我们继承的是之前的UserBase。

对应操作数据库查询用户的逻辑我们使用之前注册的时候使用的get_by_username即可。

我们把密码输入失败和token的值放在redis中,那么redis对应的配置,我们在搭建架构时已经配置好了,都放在了.env中:

ENV = "DEV"


# mysql
MYSQL_HOST = "10.30.10.36"
MYSQL_PORT = 3306
MYSQL_USERNAME = "root"
MYSQL_PASSWORD = "123456"
MYSQL_DB_DEV = "learn_onsite_system_dev"
MYSQL_DB_TEST = "learn_onsite_system_test"
MYSQL_DB_PRO = "learn_onsite_system_pro"

# redis
REDIS_HOST = "10.30.10.36"
REDIS_PORT = "6379"
REDIS_DB = "0"

而且redis初始化相关逻辑之前我是放在了mian.py主文件中,今天我将其单独提取出来维护

"""
-*- encoding=utf-8 -*-
Time: 2024/7/22 16:02
Author: lc
Email: 15101006331@163.com
File: redis.py
"""
from aioredis import Redis, create_redis_pool
from settings.config import REDIS_CONFIG


async def create_redis() -> Redis:
    return await create_redis_pool(
        f"redis://:@{REDIS_CONFIG['host']}:{REDIS_CONFIG['port']}/{REDIS_CONFIG['db']}?encoding=utf-8")

再将其导入到main.py中

from middlewares.redis import create_redis


@app.on_event("startup")
async def startup_event():
    app.state.redis = await create_redis()
    print("init redis success")
    create_tables()
    print("init database success")
    init_roles()
    print("init roles success")


@app.on_event("shutdown")
async def shutdown_event():
    app.state.redis.close()
    await app.state.redis.wait_closed()
    print("redis closed")

我们把token相关配置也配置进去

ENV = "DEV"


# mysql
MYSQL_HOST = "10.30.10.36"
MYSQL_PORT = 3306
MYSQL_USERNAME = "root"
MYSQL_PASSWORD = "123456"
MYSQL_DB_DEV = "learn_onsite_system_dev"
MYSQL_DB_TEST = "learn_onsite_system_test"
MYSQL_DB_PRO = "learn_onsite_system_pro"

# redis
REDIS_HOST = "10.30.10.36"
REDIS_PORT = "6379"
REDIS_DB = "0"


# TOKEN
SECRET_KEY = "08d25e094faa6ca2556c819756bhj9563b93f7099f6f0f4xxd6cf93b33e8d3e7"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

那么产生token的代码如何实现呢

from jose import JWTError, jwt
from settings.config import TOKEN_CONFIG


def create_access_token(data: dict):
    """产生token"""
    to_encode = data.copy()
    encoded_jwt = jwt.encode(to_encode, TOKEN_CONFIG["secret_key"], algorithm=TOKEN_CONFIG["algorithm"])
    return encoded_jwt

接下来就是根据逻辑去实现具体的登录逻辑了,在user_method.py中增加如下方法:
 

async def verify_login(request: Request, user: UserLogin, db: Session):
    logger.info("登录开始了")
    db_user = get_by_username(db, user.username)
    if not db_user:
        logger.warning(f"用户:’{user.username}‘ 不存在")
        return response(code=100205, message="用户不存在")
    verify = verify_password(user.password, db_user.password)
    if verify:
        redis_user = await request.app.state.redis.get(user.username)
        if not redis_user:
            try:
                token = create_access_token(data={"sub": user.username})
            except:
                logger.warning(f"method verify_login error: {format_exc()}")
                return response(code=100203, message="生产token失败")
            await request.app.state.redis.set(user.username, token, expire=TOKEN_CONFIG["access_token_expire_time"])
            return response()
        return response(code=100202, message="重复登录")
    else:
        error_key = user.username + "_password"
        result = await request.app.state.redis.hgetall(error_key, encoding="utf-8")
        # 没有查到认为是第一次出现错误,将次数设置为1,时间设置为当前时间
        if not result:
            current_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
            await request.app.state.redis.hmset_dict(error_key, num=1, time=current_time)
            return response(code=100206, message="密码错误")
        # 查到则不是第一次,要分多重情况
        else:
            error_num = int(result["num"])
            num_time = (datetime.now() - datetime.strptime(result["time"], "%Y-%m-%d %H:%M:%S")).seconds / 60
            # 60分钟内错误没达到3次,错误次数加1
            if error_num < 3 and num_time < 60:
                error_num += 1
                await request.app.state.redis.hmset_dict(error_key, num=error_num)
                return response(code=100206, message="密码错误")
            # 超60分钟没有达到3次,错误次数重置为1,时间设置为当前
            elif error_num < 3 and num_time > 60:
                error_num = 1
                num_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
                await request.app.state.redis.hmset_dict(error_key, num=error_num, time=num_time)
                return response(code=100206, message="密码错误")
            # 60分钟内错误超过3次,错误次数加1,限制60分钟内不可以登录
            elif error_num >= 3 and num_time < 60:
                error_num += 1
                await request.app.state.redis.hmset_dict(error_key, num=error_num)
                return response(code=100204, message="输入密码错误次数过多,账号暂时锁定,请60分钟后再来登录")
            # 超60分钟,如果再次输错,将错误次数重置为1,时间设置为当前时间
            else:
                error_num = 1
                num_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
                await request.app.state.redis.hmset_dict(error_key, num=error_num, time=num_time)
                return response(code=100206, message="密码错误")

接下来,在user.py中增加我们的登录接口

@user_router.post("/login", summary="登录")
async def login(request: Request, user: UserLogin, db: Session = Depends(create_db)):
    return await verify_login(request, user, db)

测试:

①:成功

②:密码错误

③:60分钟内连续3次登录错误

至此,我们的登录接口就完成了

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

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

相关文章

中望CAD 专业 v2024 解锁版下载与安装教程 (CAD三维制图)

前言 中望CAD软件&#xff08;ZWCAD&#xff09;是一款源自国内的自主研发CAD制图软件&#xff0c;提供二三维CAD功能&#xff0c;专注于机械设计制图领域。其最新版本&#xff0c;中望CAD采用了国际领先的CAD核心技术&#xff0c;不断优化软件性能和用户体验&#xff0c;并加…

.netcore TSC打印机打印

此文章给出两种打印案例&#xff0c; 第一种是单列打印&#xff0c;第二种是双列打印 需要注意打印机名称的设置&#xff0c;程序中使用的打印机名称为999&#xff0c;电脑中安装打印机时名称也要为999。 以下是我在使用过程中总结的一些问题&#xff1a; 一 TSC打印机使用使…

谷粒商城实战笔记-跨域问题

一&#xff0c;When allowCredentials is true, allowedOrigins cannot contain the special value “*” since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider u…

PostgreSQL 中如何处理数据的唯一性约束?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中如何处理数据的唯一性约束&#xff1f;一、什么是唯一性约束二、为什么要设置唯一性约束…

基于A律压缩的PCM脉冲编码调制通信系统simulink建模与仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1A律压缩的原理 4.2 PCM编码过程 4.3 量化噪声与信噪比 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3.部分核心程序 &#…

Atom - hackmyvm

简介 靶机名称&#xff1a;Atom 难度&#xff1a;简单 靶场地址&#xff1a;https://hackmyvm.eu/machines/machine.php?vmAtom 本地环境 虚拟机&#xff1a;vitual box 靶场IP&#xff08;Atom&#xff09;&#xff1a;192.168.56.101 跳板机IP(windows 11)&#xff1…

MySQL面试篇章——MySQL索引

文章目录 MySQL 索引索引分类索引创建和删除索引的执行过程explain 查看执行计划explain 结果字段分析 索引的底层实现原理B-树B树哈希索引 聚集和非聚集索引MyISAM&#xff08;\*.MYD&#xff0c;*.MYI&#xff09;主键索引辅助索引&#xff08;二级索引&#xff09; InnoDB&a…

线程的中互斥锁和条件变量的运用

第一题&#xff1a;使用互斥锁或者信号量&#xff0c;实现一个简单的生产者消费者模型 一个线程每秒生产3个苹果&#xff0c;另一个线程每秒消费8个苹果 #include <myhead.h>pthread_mutex_t m1,m2;int apple 0; void* usrapp(void* data) {while(1){pthread_mutex_lock…

旋转差分,以及曼哈顿距离转换切比雪夫距离

拿到这个问题我们要怎么去想呢&#xff0c;如果是暴力的修改的话&#xff0c;我们的复杂度为 m * 2r*r 的复杂度&#xff0c;这也太暴力了&#xff0c;我们要怎么办呢&#xff0c;我们能不能用差分数组来实现呢&#xff1f; 我们首先要看如何实现公式的转换 很显然我们可以利用…

<数据集>pcb板缺陷检测数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;693张 标注数量(xml文件个数)&#xff1a;693 标注数量(txt文件个数)&#xff1a;693 标注类别数&#xff1a;6 标注类别名称&#xff1a;[missing_hole, mouse_bite, open_circuit, short, spurious_copper, spur…

物联网与区块链技术的跨界融合:智能城市的建设与管理

随着科技的迅猛发展&#xff0c;物联网&#xff08;IoT&#xff09;和区块链技术逐渐成为推动智能城市发展的重要技术支柱。本文将探讨物联网和区块链技术在智能城市建设与管理中的跨界融合&#xff0c;分析其应用场景和潜力。 什么是智能城市&#xff1f; 智能城市利用先进的…

(35)远程识别(又称无人机识别)(一)

文章目录 前言 1 更改 2 可用的设备 3 开放式无人机ID 4 ArduRemoteID 5 终端用户数据的设置和使用 6 测试 7 为OEMs添加远程ID到ArduPilot系统的视频教程 前言 在一些国家&#xff0c;远程 ID 正在成为一项法律要求。以下是与 ArduPilot 兼容的设备列表。这里(here)有…

深度刨析C语言中的动态内存管理

文章目录 1.为什么会存在动态内存分配2.动态内存函数介绍2.1 [malloc](https://legacy.cplusplus.com/reference/cstdlib/malloc/?kwmalloc)与[free](https://legacy.cplusplus.com/reference/cstdlib/free/?kwfree)2.2 [calloc](https://legacy.cplusplus.com/reference/cst…

Redis - SpringDataRedis - RedisTemplate

目录 概述 创建项目 引入依赖 配置文件 测试代码 测试结果 数据序列化器 自定义RedisTemplate的序列化方式 测试报错 添加依赖后测试 存入一个 String 类型的数据 测试存入一个对象 优化 -- 手动序列化 测试存入一个Hash 总结&#xff1a; 概述 SpringData 是 S…

浏览器【WebKit内核】渲染原理【QUESTION-1】

浏览器【WebKit内核】渲染原理【QUESTION】 1.浏览器输入一个网址&#xff08;域名之后&#xff09;,浏览器会呈现一个新的页面&#xff0c;中间的过程是怎么实现的&#xff1f; 输入一个网址之后&#xff0c;首先DNS服务器会解析这个域名&#xff0c;将这个域名解析成IP地址&…

SAP 贷项销售订单简介

SAP 贷项销售订单简介 1. 什么是销售贷方销售订单?2. 创建销售贷方销售订单的场景3. 销售贷方销售订单的创建流程直接创建发票---VF01将会计凭证过账到会计核算查看贷项销售订单凭证流查看客户明细---FBL5N贷项后台配置SAP销售贷方销售订单(Sales Credit Memo Request)是销售…

北醒单点激光雷达更改id和波特率以及Ubuntu20.04下CAN驱动

序言&#xff1a; 需要的硬件以及软件 1、USB-CAN分析仪使用顶配pro版本&#xff0c;带有支持ubuntu下的驱动包的&#xff0c;可以读取数据。 2、电源自备24V电源 3、单点激光雷达接线使用can线可以组网。 一、更改北醒单点激光雷达的id号和波特率 安装并运行USB-CAN分析仪自带…

pdf压缩在线免费 pdf压缩在线免费网页版 在线pdf压缩在线免费 pdf压缩工具在线免费

在数字化时代&#xff0c;pdf文件已经成为我们工作、学习和生活中的重要组成部分。然而&#xff0c;体积庞大的pdf文件往往给我们的存储空间、传输速度带来不小的压力。本文将为您揭秘几种简单有效的pdf文件压缩方法&#xff0c;让您轻松应对文件体积过大带来的困扰。 方法一、…

C++从入门到起飞之——const成员函数Date类实现 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 代码链接&#xff1a;这篇文章代码的所有代码都在我的gitee仓库里面啦&#xff0c;需要的小伙伴点击自取哦…

【论文解读】大模型算法发展

一、简要介绍 论文研究了自深度学习出现以来&#xff0c;预训练语言模型的算法的改进速度。使用Wikitext和Penn Treebank上超过200个语言模型评估的数据集(2012-2023年)&#xff0c;论文发现达到设定性能阈值所需的计算大约每8个月减半一次&#xff0c;95%置信区间约为5到14个月…