【自学开发之旅】Flask-会话保持-API授权-注册登录

news2024/11/28 14:43:28

http - 无状态-无法记录是否已经登陆过
#会话保持 – session cookie
session – 保存一些在服务端
cookie – 保存一些数据在客户端

session在单独服务器D上保存,前面数个服务器A,B,C上去取就好了,业务解耦。—》》现在都是基于token的验证。
以上是基于BS架构

API授权
由服务端完全把控
三张表,api_token,app_permission,api_permission
多对多的关系:一个账号(服务端给的)可以有多个url权限,同一个url可以被多个账号授权。

models/user.py

from . import db

#API授权表的模型
#多对多的关系  中间表
app_permission = db.Table("app_permission",
                          db.Column("api_id",db.ForeignKey("api_token.id")),
                          db.Column("permission_id",db.ForeignKey("api_permission.id"))
                          )
# api_token表
#存放的是授权密钥,以及授权id
class ApiToken(db.Model):
    __tablename__ = "api_token"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    appid = db.Column(db.String(128), nullable=False)
    secretkey = db.Column(db.String(128), nullable=False)
    #通过中间表去创建多对多的关系
    manage = db.relationship("ApiPermission", secondary=app_permission, backref="token")

#存放的是授权的url
class ApiPermission(db.Model):
    __tablename__ = "api_permission"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    url = db.Column(db.String(128), nullable=False)
    method_type = db.Column(db.String(128), nullable=False)

新增了文件,记得一定要“用到”我们的项目,绑定,运行了没有?
在init文件里加入

from . import user

然后生效到数据库里
terminal

flask --app server:sq_app db migrate
flask --app server:sq_app db upgrade

在Python中,如果你想在不改变业务逻辑源代码的情况下添加额外功能,你可以使用以下几种方法:

使用装饰器:装饰器可以在不改变函数或方法代码的情况下,添加额外的功能。例如,你可以使用装饰器来记录函数执行的时间,或者验证函数的输入。

def timing_decorator(func):  
    def wrapper(*args, **kwargs):  
        start = time.time()  
        result = func(*args, **kwargs)  
        end = time.time()  
        print(f"{func.__name__} took {end - start} seconds")  
        return result  
    return wrapper  
  
@timing_decorator  
def my_function():  
    # your code here

使用继承:如果你想要在不改变类的方法的情况下添加额外功能,你可以创建一个新的类,继承自原始类,并在新的类中添加额外的方法。

class OriginalClass:  
    # original methods here  
  
class NewClass(OriginalClass):  
    def extra_method(self):  
        # extra functionality here

使用Mixin:Mixin是一种设计模式,它允许你在不修改类的情况下,将额外的功能添加到类中。你可以创建一个Mixin类,其中包含你想要添加的额外方法,然后让这个类继承自原始类。

class MixinClass:  
    def extra_method(self):  
        # extra functionality here  
  
class OriginalClass:  
    # original methods here  
  
class NewClass(OriginalClass, MixinClass):  
    pass  # NewClass now has all the methods of OriginalClass and MixinClass

使用AOP(面向切面编程):AOP是一种编程范式,它允许程序员将横切关注点(cross-cutting concerns)从它们所影响的业务逻辑中分离出来。这种范式在处理一些“在哪里执行代码”的问题时特别有用,比如日志记录、事务处理、安全检查等。Python的某些库如Aspectlib、Hybrid等支持这种范式。
使用Monkey Patching:Monkey Patching是一种动态(运行时)修改模块或类的技术。使用这种方法,你可以在不修改源代码的情况下添加或改变功能。然而,这种方法应该谨慎使用,因为它可能会导致代码难以理解和维护。

libs/auth.py

from flask import request
from models.user import ApiToken, ApiPermission
from hashlib import md5
# import time

def auth_required(func):
    def inner(*args, **kwargs):
        if api_auth():
            return func(*args, **kwargs)
        else:
            return "认证失败"
    return inner

# api授权认证函数  --  函数返回为真表示认证成功
# 哈希算法 -- md5单向加密
def api_auth():
    params = request.args  # 客户端url传递过来的参数
    appid = params.get("appid")
    salt = params.get("salt")  # 盐值
    sign = params.get("sign")  # 签名
    timestamp = params.get("timestamp")  # 时间戳

    # if time.time() - int(timestamp) > 600:
    #     return False

    api_token = ApiToken.query.filter_by(appid=appid).first()
    if not api_token:
        return False

    # 验证有没有此url和方法的权限
    # http://127.0.0.1:8000/v1/monitor   GET
    #                                /v1/monitor         get
    if not has_permission(api_token, request.path, request.method.lower()):
        return False
    # 获取数据库里的密钥

    secretkey = api_token.secretkey
    # 生成服务端的签名
    # 可以加上时间戳来防止签名被别人盗取,重复访问
    # user_sign = appid + salt + secretkey
    user_sign = appid + salt + secretkey ##+ timestamp
    m1 = md5()
    m1.update(user_sign.encode(encoding="utf-8"))
    # 判断客户端传递过来的签名和服务端生成签名是否一致
    if sign != m1.hexdigest():
        # raise AuthFailException
        return False
    else:
        return True


def has_permission(api_token, url, method):
    # 客户端请求的方法和url
    # get/v1/monitor
    mypermission = method + url
    # 获取此api_token对象的所有url权限
    all_permission = [permission.method_type + permission.url
                      for permission in api_token.manage]
    # ['get/v1/monitor', 'post/v1/monitor']

    if mypermission in all_permission:
        return True
    else:
        return False

router/product_view/product_api.py

from libs.auth import auth_required


class ProductView(Resource):
    # @装饰器
    @auth_required
    def get(self, id = None):

api授权流程
1.客户端向服务端申请授权,服务端向客户端提供appid和secretkey,以及加密算法
2.客户端按照服务端提供的信息、算法,生成签名,请求时发送给服务端
3.服务端收到信息,验证是否成功

客户端请求代码libs/api_auth_clilent.py

import requests
import random
import hashlib


def calculate_sign(appid, salt, secretkey):
    user_sign = appid + salt +secretkey
    m1 = hashlib.md5()
    m1.update(user_sign.encode(encoding='utf-8'))
    return m1.hexdigest()

length_of_string = random.randint(1, 10)
appid = "sc"
salt = "JD"
secretkey = "123456"

sign =calculate_sign(appid, salt, secretkey)

url = 'http://127.0.0.1:9000/v1/product'
params = {
    'appid': appid,
    'salt': salt,
    'sign': s ign
}
response = requests.get(url, params=params)
if response.status_code == 200:
    print(response.json())
else:
    print(f"请求失败,状态码:{response.status_code}")

运行结果:
在这里插入图片描述
为了更安全,可以加入时间戳

注册登录
models/user.py

"""
@date: 2023/9/16
@file: user
@author: Jiangda
@desc: test

"""


from . import db
from werkzeug.security import generate_password_hash
import datetime

#API授权表的模型
#多对多的关系  中间表
app_permission = db.Table("app_permission",
                          db.Column("api_id",db.ForeignKey("api_token.id")),
                          db.Column("permission_id",db.ForeignKey("api_permission.id"))
                          )
# api_token表
#存放的是授权密钥,以及授权id
class ApiToken(db.Model):
    __tablename__ = "api_token"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    appid = db.Column(db.String(128), nullable=False)
    secretkey = db.Column(db.String(128), nullable=False)
    #通过中间表去创建多对多的关系
    manage = db.relationship("ApiPermission", secondary=app_permission, backref="token")

#存放的是授权的url
class ApiPermission(db.Model):
    __tablename__ = "api_permission"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    url = db.Column(db.String(128), nullable=False)
    method_type = db.Column(db.String(128), nullable=False)

class User(db.Model):
    __tablename__ = "userdb"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(128), nullable = False)
    _password = db.Column("password", db.String(128), nullable=False)
    role = db.Column(db.Integer, default=0)
    add_time = db.Column(db.DateTime, default = datetime.datetime.now)

    # 属性包装装饰器:python内置装饰器
    # 作用:把方法当作属性一样使用,定义属性之前做一些检测、转换
    #
    @property   #自动根据函数名生成两个装饰器 ==》password.setter password.delete
    def password(self):
        return self._password
    # user.password()  -->print(user.password)

    @password.setter
    def password(self, value):
        self._password = generate_password_hash(value)

    @classmethod  #类方法 第一个参数代表类本身
    def create_user(cls, username, password):
        user = cls() #创建实例对象
        user.username = username
        user.password = password #调用password.setter装饰的函数,强制性要求存hash值
        db.session.add(user)
        db.session.commit()

在这里插入图片描述
在这里插入图片描述

接着,对数据进行校验(密码合法性什么的,有专门的库)
pip install wtforms DataRequired, Regexp, ValidationError

forms/user.py

from wtforms import Form, StringField
from wtforms.validators import DataRequired, Regexp, ValidationError
from models.user import User

class Userform(Form):
    username = StringField(validators=[DataRequired()])
    password = StringField(validators=[DataRequired(), Regexp(r'\w{6,18}', message="密码不符合要求")])

#     自定义验证器,验证用户名是否唯一
#     自定义检查字段 方法名:validate_你要检查的字段
    def validate_username(self, value):
        if User.query.filter_by(username = value.data).first():
            raise  ValidationError("用户已存在")

修改router/user/user.py(做了数据校验的版本)

from flask import request
from . import user_bp
from flask_restful import Resource, Api
from models.user import User
from libs.response import generate_response
from forms.user import Userform


api = Api(user_bp)

class UserRegister(Resource):
# post方法 -- json  /v1/user

    # # 没做数据校验的版本(如下)
    # def post(self):
    #     username = request.json.get("username")
    #     password = request.json.get("password")
    #
    #     if username is not None:
    #         if password is not None:
    #             new_user = User.create_user(username, password)
    #             return generate_response(msg="register success!")
    #         else:
    #             return generate_response(msg="register fail!", code=20)
    #     else:
    #         return generate_response(msg="no username", code=21)


    #做了数据校验的版本
    def post(self):
        #try:
            data = request.json
            form = Userform(data=data)
            if form.validate():
                User.create_user(
                    username = data.get("username"),
                    password = form.password.data)
                return  generate_response(msg="注册成功", code=0)
            else:
                return generate_response(code=1, msg=form.errors)
        #except:
           #return generate_response(code=1, msg="注册失败!")

api.add_resource(UserRegister,"/user")

在这里插入图片描述

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

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

相关文章

stm32学习笔记:GPIO输入

1、寄存器输入输出函数 //读取输入数据寄存器某一个端口的输入值,参数用来指定某一个端口,返回值是 uint8_t类型,用来代表高低电平(读取按键的值)uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_…

JVM调优笔记

双亲委派机制 app---->ext----->bootstrap 保证系统的核心库不被修改 沙箱安全机制 限制系统资源访问,将java代码限制在虚拟机特定的运行范围中 基本组件 字节码校验器 确保java类文件遵循java规范,帮助java程序实现内存保护类加载器 native…

基于SSM的北京集联软件科技有限公司信息管理系统

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

博客摘录「 MobaXterm登录密码重置」2023年9月21日

登录MobaXterm提示输入密码, 而且还 忘记密码 安装重置密码的工具 可以使用浏览器打开 如下网址: https://mobaxterm.mobatek.net/resetmasterpassword.html 打开如图: 下载MobaXterm软件密码重置工具,下载好并解压后 直接…

第二证券:创业板指失守2000点 算力概念股走势活跃

周三,沪深两市继续缩量震动调整,三大指数均小幅下跌,创业板指失守2000点整数关口,再创调整新低。到收盘,上证综指报3108.57点,跌0.52%;深证成指报10072.46点,跌0.53%;创业…

Python机器学习实战-特征重要性分析方法(1):排列重要性(附源码和实现效果)

实现功能 排列重要性 PermutationImportance:该方法会随机排列每个特征的值,然后监控模型性能下降的程度。如果获得了更大的下降意味着特征更重要 实现代码 from sklearn.datasets import load_breast_cancer from sklearn.ensemble import RandomFore…

应用程序处理:TCP模块的处理

1、应用程序处理 首先应用程序会进行编码处理,这些编码相当于 OSI 的表示层功能; 编码转化后,邮件不一定马上被发送出去,这种何时建立通信连接何时发送数据的管理功能,相当于 OSI 的会话层功能。 2、TCP 模块的处理 …

共聚焦显微镜在化学机械抛光课题研究中的应用

两个物体表面相互接触即会产生相互作用力,研究具有相对运动的相互作用表面间的摩擦、润滑与磨损及其三者之间关系即为摩擦学,目前摩擦学已涵盖了化学机械抛光、生物摩擦、流体摩擦等多个细分研究方向,其研究的数值量级也涵盖了亚纳米到百微米…

MYSQL不常用但好用写法

ORDER BY FIELD() 自定义排序逻辑 MySql 中的排序 ORDER BY 除了可以用 ASC 和 DESC,还可以通过 「ORDER BY FIELD(str,str1,…)」 自定义字符串/数字来实现排序。这里用 order_diy 表举例,结构以及表数据展示: ORDER BY FIELD(str,str1,…) …

【Excel加密】excel只读模式在哪里设置

Excel文件想要设置成只读模式,其实很简单,今天给大家分享四个excel设置只读模式的方法。 方法一:文件属性 右键点击文件,查看文件属性,在属性界面,勾选上只读属性就可以了。 方法二:始终以只读…

pixel2的root过程

用adb连接手机 首先学会用adb连接手机 可以配置在主机Windows和虚拟机上 手机打开设置,连续点击版本号进入开发者模式 点击进入开发者选项,允许USB调试,连接在电脑上,在手机授权对话框中允许电脑调试 连接完成后,输…

eslint代码校验及修复(Vue项目快速上手)

项目中配置eslint校验 文章目录 项目中配置eslint校验前言1. webpack5搭建 Vue项目如下🔗(可以查看)2. eslint+prettier Vue项目如下🔗(暂时未更新)一、什么是 ESLint?二、为什么要使用 ESLint?三、如何在 Vue 项目中集成 ESLint?3.1.安装依赖代码如下:如下图所示3…

视频定格合璧,批量剪辑轻松插入图片

大家好!想要将视频与图片完美融合吗?现在,我们为您推出一款强大的批量剪辑工具,让您能够轻松在图片中插入视频,让您的创作更加精彩动人! 首先,第一步我们要进入媒体梦工厂主页面,并…

Wolfram语言之父:ChatGPT到底能做什么? | 阿Q送书第六期

文章目录 那么,ChatGPT到底在做什么?它为什么能做到这些?前方的路为ChatGPT赋予“思想”留言提前获赠书 人类语言及其背后的思维模式在结构上比我们想象的更简单、更“符合规律”。 ChatGPT大火,甚至已经开始改变人类的工作和思考…

好用的Mac笔记本电脑文件清理工具CleanMyMac

Mac系统进行文件清理,一般是直接将文件拖动入“废纸篓”回收站中,然后通过清理回收站,就完成了一次文件清理的操作,但是这么做并无法保证文件被彻底删除了,有些文件通过一些安全恢复手段依旧是可以恢复的,那…

vue项目通过json-bigint在前端处理java雪花id过长导致失去精度问题

这里 我简单模仿了一个接口 这里 我单纯 返回一个long类型的雪花id 然后 前端 用 axios 去请求 大家知道 axios 会对请求数据做一次处理 而我们 data才是拿到我们java这边实际返回的东西 简单说 就是输出一下我们后端返回 的内容 这里 我们网络中显示的是 35866101868095488…

离散数学 学习 之一阶逻辑的前束范式

敲重点 如果是蕴含式的前件要改变符号,后件不需要

springboot导入excel(POI)

POI官方文档 引入依赖 <!--POI--><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId&…

FOXBORO FBM230 P0926GU 数字量控制模块

FOXBORO FBM230 P0926GU 数字量控制模块是用于工业自动化和过程控制系统的模块之一&#xff0c;用于处理数字量信号&#xff0c;例如开关状态、传感器状态等。这些模块广泛应用于各种工业领域&#xff0c;包括但不限于以下应用领域&#xff1a; 工业自动化&#xff1a;在工业自…

<Altium Designer> 将.DSN文件导入并转换成SchDoc文件

目录 01 使用向导方式导入.DSN 02 消除Unique Identifiers Errors 03 文章总结 大家好&#xff0c;这里是程序员杰克。一名平平无奇的嵌入式软件工程师。 本文主要是总结和分享将OrCAD Capture画的原理图文件(.DSN)导入到Altium Designer&#xff0c;转换成对应的原理图文件…