【Flask】会话保持-API授权-注册登录

news2025/1/14 18:10:51

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/1016660.html

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

相关文章

SpringMVC自定义注解和使用

一.引言 1.简介: 在Spring MVC中,我们可以使用自定义注解来扩展和定制化我们的应用程序。自定义注解是一种通过Java的注解机制定义的特殊注解,可以应用于控制器类、方法或者方法参数上,以实现不同的功能和行为。(注解…

[uni-app] iOS/Android端 禁止单个页面侧滑返回的处理记录

需要禁止部分页面侧滑返回 iOS端 popGesture 但是实测后, 其实设置popGesture:none 是无效的 真正可以用的是这个 disableSwipeBack android端 别的方案没有逐一尝试, 这边可以在需要禁止的页面的 onBackPress onBackPress() {// 禁止侧滑(但注意也会禁止导航返回,导航返…

如何在外网访问公司项目?快解析实现内网ip让公网连接

随着互联网技术的不断发展,越来越多的企业和个人选择使用服务器进行网站或应用程序的部署。公司内部项目需要提供外网访问是个常见的网络场景,需要怎么操作设置也是网络或项目人员需要关注的。 企业使用服务器搭建公司业务系统一般会使用云服务器或者使…

最新AI创作系统ChatGPT源码/支持国内AI模型/支持GPT4.0/支持AI绘画

一、AI创作系统 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT系统?小编这里写一个详细图文教程吧&am…

WebGPU学习(10)---如何利用 WebGPU 实现高性能

虽然是WebGPU,但是速度很慢!? 我们将解释如何充分利用 WebGPU 性能。这次我们以绘制大量物体为例,根据“使用纹理”中的代码进行一些更改并绘制 900 个立方体。 要均匀分布立方体,可以按如下方式更新 worldMatrix&am…

微信小程序 解决 当套在scroll-view中后 wx.pageScrollTo 函数失效问题解决

pageScrollTo 只是 页面的API 他对 scroll-view 的滚动是无法控制的 但是 scroll-view 也提供了一个scroll-into-view属性 我们编写一个小案例 wxml 参考代码如下 <view><scroll-view scroll-y"{{ true }}" style"height: 100vh;" scroll-into-v…

笑笑云航服悦《乡村振兴战略下传统村落文化旅游设计》许少辉博士新著

笑笑云航服悦《乡村振兴战略下传统村落文化旅游设计》许少辉博士新著

Android高级开发-APK极致优化

九道工序 1. SVG(Scalable Vector Graphics)可缩放矢量图 使用矢量图代替位图可以减小 APK 的尺寸&#xff0c;因为可以针对不同屏幕密度调整同一文件的大小&#xff0c;而不会降低图像质量。 矢量图首次加载时可能消耗更多的 CPU 资源。之后&#xff0c;二者的内存使用率和…

Spring 篇

1、什么是 Spring&#xff1f; Spring是一个轻量级的IOC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架&#xff0c;目的是用于简化企业应用程序的开发&#xff0c;它使得开发者只需要关心业务需求。常见的配置方式有三种&#xff1a;基于XML的配置、基于注解的配置…

06JVM_类加载器

一、类加载器 以JDK8为例&#xff1a; ①启动类加载器 ②扩展类加载器 ③应用程序类加载器 ④自定义类加载器 ①类加载器具有层级关系&#xff0c;当加载一个类的时候&#xff0c;要看所有的上级有没有加载此类。【双亲委派模式】 ②类加载器负责在运行时将Java类动态加载…

4.开放-封闭原则

这个原则其实是有两个特征&#xff0c;一个是说‘对于扩展是开放的(Open for extension)&#xff0c;另一个是说‘对于更改是封闭的(Closed for modification)[ASD]。

走近Callable

1.特点 可以有返回值可以抛出异常方法不同&#xff0c; run() / call(); Callable 接口类似于Runnable &#xff0c;因为它们都是为其实例可能有另一个线程执行的类设计的&#xff0c; 然而&#xff0c;Runnable不返回结果&#xff0c;也不能抛出被检查的异常。 2.代码测试…

互联网数字化管理升级,制造企业一站式智能管理,可定制-亿发

在互联网时代&#xff0c;传统机械制造企业面临着未有的挑战和机遇。信息化管理水平成为企业竞争力的关键因素。然而&#xff0c;许多制造企业在信息化管理中常常陷入以下三大问题&#xff1a; 1、盲目随潮流&#xff0c;缺乏总体规划 互联网时代&#xff0c;科技发展日新月异…

python基础复习-基本数据类型

目录 数字进制转换小数精度科学计算库 字符串转义符正向/反向索引正向/反向切片成员运算字符编码字符串处理 布尔类型指示条件作为掩码 类型转换 数字 进制转换 a10 bbin(a) coct(a) dhex(a) print(a,b,c,d) print(type(a)) print(type(b)) print(type(c)) print(type(d))10 …

Spring Cloud超越微服务:服务网格的崭露头角

文章目录 1. 微服务的挑战2. 什么是服务网格&#xff1f;3. Spring Cloud和服务网格服务发现负载均衡安全性服务网格扩展 4. 服务网格的优势4.1. 解耦通信逻辑4.2. 提高可观察性4.3. 灰度发布和流量控制4.4. 安全性 5. 未来展望6. 结论 &#x1f389;欢迎来到架构设计专栏~Spri…

【办公自动化】用Python在Excel中查找并替换数据(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Python 潮流周刊#20:三种基准测试的方法、为什么代码在函数中运行得更快?

△点击上方“Python猫”关注 &#xff0c;回复“1”领取电子书 你好&#xff0c;我是猫哥。这里每周分享优质的 Python、AI 及通用技术内容&#xff0c;大部分为英文。标题取自其中两则分享&#xff0c;不代表全部内容都是该主题&#xff0c;特此声明。 本周刊由 Python猫 出品…

【Qt】Qt中关联容器QMap,QMultiMap,QHash,QMultiHash 的理解

在Qt中&#xff0c;有几种关联容器可供选择&#xff1a; QMap&#xff1a;QMap是一个关联容器&#xff0c;存储键-值对&#xff0c;并根据键自动进行排序。它提供了快速的查找和插入操作&#xff0c;适用于需要根据键进行排序和搜索的场景。 QMultiMap&#xff1a;QMultiMap是…

软件测评中:电子政务系统怎么测评?

1、文件依据&#xff1a; 1)《中华人民共和国政府采购法实施条例》&#xff08;中华人民共和国国务院令 第658号&#xff09; 第四十一条“大型或者复杂的政府采购项目&#xff0c;应当邀请国家认可的质量检测机构参加验收工作。” 2) 《国务院办公厅关于印发国家政务信息化…

深入Android系统基础知识及基本概念

深入Android系统基础知识及基本概念 Android应用程序的基本组成部分&#xff0c;包括Activities&#xff08;活动&#xff09;、Services&#xff08;服务&#xff09;、Broadcast receivers&#xff08;广播接收器&#xff09;和Content providers&#xff08;内容提供者&…