Go语言实现OAuth 2.0认证服务器
文章目录
- 1. 项目概述
- 1.1 OAuth2 流程
- 2. OAuth 2.0 Storage接口解析
- 2.1 基础方法
- 2.2 客户端管理相关方法
- 2.3 授权码相关方法
- 2.4 访问令牌相关方法
- 2.5 刷新令牌相关方法
- 2.6 方法调用时序
- 2.7 关键注意点
- 3. MySQL存储实现原理
- 3.1 数据库设计
- 3.2 核心实现
- 4. OAuth 2.0授权码流程时序图
- 5. 使用示例
- 5.1 初始化存储
- 5.2 创建OAuth服务器
- 5.3 实现授权端点
- 5.4 实现客户端令牌端点
- 5.5 Callback回调断点(code换access_token)
- 完整流程
- 6. 总结
1. 项目概述
在上一篇文章中,我们详细介绍了OAuth 2.0的基本概念、授权流程以及各种授权模式的应用场景。本文将使用Go语言实现一个完整的OAuth 2.0认证服务器。
我们选择了github.com/openshift/osin
这个成熟的OAuth 2.0框架作为基础,重点实现了其MySQL 来作为storage的驱动。osin
提供了OAuth 2.0服务器的核心功能,但它的存储接口需要我们自己实现。通过实现MySQL存储,我们可以将OAuth 2.0的授权数据持久化到数据库中,使得服务更加可靠和可扩展。
本文的完整代码:oauth2
1.1 OAuth2 流程
让我们通过一个流程图来说明这些方法在 OAuth2 授权码模式中的位置:
2. OAuth 2.0 Storage接口解析
osin库中的Storage接口是实现OAuth 2.0服务器的核心,它定义了所有必要的存储操作。让我们详细解析每个方法在OAuth 2.0流程中的作用:
2.1 基础方法
Clone() Storage // 克隆存储实例,用于处理并发访问
Close() // 关闭存储连接,释放资源
2.2 客户端管理相关方法
GetClient(id string) (Client, error)UpdateClient(c Client) errorCreateClient(c Client) errorRemoveClient(id string) error
这些方法负责OAuth客户端的CRUD操作:
GetClient
: 根据客户端ID获取客户端信息,用于验证客户端身份UpdateClient
: 更新客户端信息CreateClient
: 创建新的客户端RemoveClient
: 删除指定客户端
2.3 授权码相关方法
SaveAuthorize(data *AuthorizeData) errorLoadAuthorize(code string) (*AuthorizeData, error)RemoveAuthorize(code string) error
这些方法处理授权码授权流程:
SaveAuthorize
: 保存授权码信息LoadAuthorize
: 验证授权码有效性RemoveAuthorize
: 使用后删除授权码
这组方法用于处理授权码的生命周期:
2.4 访问令牌相关方法
SaveAccess(data *AccessData) errorLoadAccess(token string) (*AccessData, error)RemoveAccess(token string) error
这些方法处理访问令牌的生命周期:
SaveAccess
: 保存访问令牌LoadAccess
: 验证访问令牌RemoveAccess
: 撤销访问令牌
访问令牌的生命周期管理:
2.5 刷新令牌相关方法
LoadRefresh(token string) (*AccessData, error)RemoveRefresh(token string) error
这些方法处理刷新令牌:
LoadRefresh
: 加载刷新令牌对应的访问令牌数据RemoveRefresh
: 删除刷新令牌
刷新令牌的处理流程:
2.6 方法调用时序
在完整的 OAuth2 流程中,这些方法的调用顺序如下:
2.7 关键注意点
-
原子性:
- SaveAuthorize 和 SaveAccess 操作需要保证原子性
- RemoveAuthorize 和 SaveAccess 通常需要在同一事务中执行
-
安全性:
- 所有存储的令牌数据应该加密
- 实现适当的过期机制
-
性能考虑:
- LoadAccess 方法会频繁调用,应考虑缓存
- Clone 方法对并发性能很重要
-
数据一致性:
- 确保授权码只能使用一次
- 正确处理令牌过期
- 维护刷新令牌与访问令牌的关联
3. MySQL存储实现原理
3.1 数据库设计
项目使用了两个主要的数据表:
CREATE TABLE client (id varchar(255) NOT NULL PRIMARY KEY,secret varchar(255) NOT NULL,extra text,redirect_uri varchar(255) NOT NULL,created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
)CREATE TABLE token (id varchar(255) NOT NULL PRIMARY KEY,client_id varchar(255) NOT NULL,type varchar(20) NOT NULL, access_token varchar(255), refresh_token varchar(255), code varchar(255), expires_in int NOT NULL,scope varchar(255),redirect_uri varchar(255) NOT NULL,state varchar(255),extra text,created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,expires_at timestamp NULL
)
3.2 核心实现
我们的MySQL存储实现主要包含以下特点:
- 使用
go-zero
框架的sqlx
包进行数据库操作 - 实现了完整的事务支持
- 支持令牌过期检查
- 提供了表前缀支持,便于多租户场景
4. OAuth 2.0授权码流程时序图
5. 使用示例
5.1 初始化存储
func initStorage(svcCtx *svc.ServiceContext) *service.Storage {storage := service.NewStorage(svcCtx, "oauth2_")err := storage.CreateSchemas()if err != nil {panic(err)}return storage
}
5.2 创建OAuth服务器
// newOAuthServer 创建一个新的OAuth服务器实例
func newOAuthServer(svc *svc.ServiceContext) *osin.Server {config := osin.NewServerConfig()config.AllowedAuthorizeTypes = osin.AllowedAuthorizeType{osin.CODE}config.AllowedAccessTypes = osin.AllowedAccessType{osin.AUTHORIZATION_CODE,osin.REFRESH_TOKEN,}config.AuthorizationExpiration = 600 // 10分钟config.AccessExpiration = 3600 // 1小时config.AllowGetAccessRequest = trueconfig.ErrorStatusCode = 401storage := service.NewStorage(svc, "osin_")server := osin.NewServer(config, storage)return server
}
5.3 实现授权端点
func AuthorizeHandler(svc *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {server := newOAuthServer(svc)resp := server.NewResponse()defer resp.Close()if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {// 验证客户端if ar.Client == nil {resp.SetError("unauthorized_client", "客户端未授权")osin.OutputJSON(resp, w, r)return}// 验证重定向URIif ar.RedirectUri == "" {resp.SetError("invalid_request", "缺少重定向URI")osin.OutputJSON(resp, w, r)return}ar.Authorized = true// 完成授权请求,这里只会返回授权码server.FinishAuthorizeRequest(resp, r, ar)// 如果没有错误,会重定向到客户端的redirect_uri,并带上授权码if !resp.IsError {resp.Type = osin.REDIRECT}}// 输出响应(可能是重定向或错误信息)osin.OutputJSON(resp, w, r)}
}
5.4 实现客户端令牌端点
func TokenHandler(svc *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {logger := logx.WithContext(r.Context())server := newOAuthServer(svc)resp := server.NewResponse()defer resp.Close()if ar := server.HandleAccessRequest(resp, r); ar != nil {// 验证客户端if ar.Client == nil {resp.SetError("unauthorized_client", "客户端未授权")osin.OutputJSON(resp, w, r)return}// 授权请求ar.Authorized = trueserver.FinishAccessRequest(resp, r, ar)}if resp.IsError {logger.Errorf("Token error: %v", resp.InternalError)} else {logger.Infof("Token granted: %s", resp.Output["access_token"])}osin.OutputJSON(resp, w, r)}
}
5.5 Callback回调断点(code换access_token)
func CallbackHandler(svc *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {// 获取授权码code := r.URL.Query().Get("code")if code == "" {// 检查是否有错误信息if error := r.URL.Query().Get("error"); error != "" {errorDesc := r.URL.Query().Get("error_description")http.Error(w, fmt.Sprintf("授权失败: %s - %s", error, errorDesc), http.StatusBadRequest)return}http.Error(w, "未收到授权码", http.StatusBadRequest)return}// 初始化 OAuth 服务器server := newOAuthServer(svc)// 先加载授权数据authData, err := server.Storage.LoadAuthorize(code)if err != nil {resp := server.NewResponse()resp.SetError("invalid_grant", "授权码无效或已过期")osin.OutputJSON(resp, w, r)return}// 创建访问令牌请求ar := &osin.AccessRequest{Type: osin.AUTHORIZATION_CODE,Code: code,Client: authData.Client,RedirectUri: authData.RedirectUri,Scope: authData.Scope,GenerateRefresh: true,Authorized: true,Expiration: server.Config.AccessExpiration,}// 处理访问令牌请求resp := server.NewResponse()defer resp.Close()if err := server.Storage.RemoveAuthorize(code); err != nil {resp.SetError("server_error", "无法删除授权码")osin.OutputJSON(resp, w, r)return}server.FinishAccessRequest(resp, r, ar)if resp.IsError {osin.OutputJSON(resp, w, r)return}// API 请求则返回 JSONosin.OutputJSON(resp, w, r)}
}
完整流程
关键流程说明
- 授权码获取:
- 客户端首先访问/oauth/authorize端点获取授权码
- 服务器生成授权码并保存到数据库
- 授权码换取令牌:
- 客户端带着授权码访问/oauth/callback端点
- CallbackHandler负责验证授权码并换取访问令牌
- 这一步通常在实际应用中是由前端页面完成的,但在我们的实现中直接由后端处理
- 令牌生成流程:
- 验证授权码有效性
- 删除已使用的授权码(确保一次性使用)
- 生成访问令牌和刷新令牌
- 将令牌信息返回给客户端
6. 总结
本项目实现了一个完整的OAuth 2.0认证服务器,通过实现osin的Storage接口,提供了可靠的MySQL存储层。主要特点包括:
- 完整实现OAuth 2.0规范
- 可靠的MySQL存储实现
- 支持授权码和刷新令牌流程
- 完善的错误处理和安全机制
- 易于扩展和定制
通过这个实现,我们可以快速搭建起一个生产级别的OAuth 2.0认证服务器,为各类应用提供标准的身份认证服务。
相关文章:
Go语言实现OAuth 2.0认证服务器
文章目录 1. 项目概述1.1 OAuth2 流程 2. OAuth 2.0 Storage接口解析2.1 基础方法2.2 客户端管理相关方法2.3 授权码相关方法2.4 访问令牌相关方法2.5 刷新令牌相关方法 2.6 方法调用时序2.7 关键注意点3. MySQL存储实现原理3.1 数据库设计3.2 核心实现 4. OAuth 2.0授权码流程…...
【版本控制】idea中使用git
大家好,我是jstart千语。接下来继续对git的内容进行讲解。也是在开发中最常使用,最重要的部分,在idea中操作git。目录在右侧哦。 如果需要git命令的详解: 【版本控制】git命令使用大全-CSDN博客 一、配置git 要先关闭项目…...
永磁同步电机控制中,滑模观测器是基于反电动势观测转子速度和角度的?扩展卡尔曼滤波观测器是基于什么观测的?扩展卡尔曼滤波观测器也是基于反电动势吗?
滑模观测器在PMSM中的应用: 滑模观测器是一种非线性观测器,利用切换函数设计,使得状态估计误差迅速趋近于零,实现快速响应和对外部干扰的鲁棒性。 在永磁同步电机(PMSM)无传感器控制中,滑模观测…...
十倍开发效率 - IDEA 插件之RestfulBox - API
提高效率不是为了完成更多的任务,而是有充足的时间摸鱼。 快速体验 RestfulBox - API 是 IDEA 的插件,适合本地测试接口,完全不需要对项目进行任何以来。 接口管理:支持接口扫描、浏览、搜索、跳转、导入和导出。支持接口请求&a…...
HTML、CSS 和 JavaScript 常见用法及使用规范
一、HTML 深度剖析 1. 文档类型声明 HTML 文档开头的 <!DOCTYPE html> 声明告知浏览器当前文档使用的是 HTML5 标准。它是文档的重要元信息,能确保浏览器以标准模式渲染页面,避免怪异模式下的兼容性问题。 2. 元数据标签 <meta> 标签&am…...
人工智能概念股投资:10大潜力标的深度研究
人工智能概念股投资:10大潜力标的深度研究 一、人工智能概念股投资的基本概念 人工智能(Artificial Intelligence,AI)是指利用计算机程序模拟人类智能的一种技术,通过对数据的分析和学习,实现类似人类思维和…...
centos部署的openstack发布windows虚拟机
CentOS上部署的OpenStack可以发布Windows虚拟机。在CentOS上部署OpenStack后,可以通过OpenStack平台创建和管理Windows虚拟机。以下是具体的步骤和注意事项: 安装和配置OpenStack: 首先,确保系统满足OpenStack的最低硬件…...
Fortran 中使用 C_LOC 和 C_F_POINTER 结合的方法来实现不同类型指针指向同一块内存区域
在 Fortran 中,可以使用 C_LOC 和 C_F_POINTER 结合的方法来实现不同类型指针指向同一块内存区域。以下是具体方法和示例: 关键步骤: 获取内存地址:用 C_LOC 获取原始数组的 C 地址。类型转换:用 C_F_POINTER 将地址转…...
两个 STM32G0 I2C 通信异常的案例分析
1. 案例一问题描述 客户反馈其产品在使用 STM32G0C1NEY6TR 和一个充电管理 IC 通信时,速率为100KHz 时通信正常,但工作在 400KHz 时,有时会产生 I2C 错误。 把 I2C GPIO 配置为推挽输出后产生错误的概率会下降。 2. 案例一问题确认 针对客…...
尚硅谷-react[1-6集]
目录 步骤 1. devlopment.js 2. react-dom.devopment.js 3. babel.min.js // 将jsx转为js体验 // 这个虚拟dom的内容不能够写引号,单引号双引号 const VDOM <h1>nihao react</h1> // 可以使用括号进行编写 const VDOM1 (<h1>nihao react</h1> )…...
树状数组简单介绍
树状数组简单介绍 前言树状数组(Binary Indexed Tree)JavaScript 详细指南一、什么是树状数组?二、核心概念(前置知识):lowbit 函数三、树状数组的实现1. 初始化树状数组2. 使用示例 四、详细原理解释1. 树…...
使用Redis实现分布式限流
一、限流场景与算法选择 1.1 为什么需要分布式限流 在高并发系统中,API接口的突发流量可能导致服务雪崩。传统的单机限流方案在分布式环境下存在局限,需要借助Redis等中间件实现集群级流量控制。 1.2 令牌桶算法优势 允许突发流量:稳定速…...
【MySQL学习】存储过程
目录 一、定义 二、基本语法 1.创建存储过程 2.删除存储过程 3.查看存储过程 三、控制语句 1.变量声明与赋值 四、游标(Cursor) (1)声明游标 (2)处理游标结束 (3)打开游标 …...
Bp靶场 - Jwt
你知道JWT漏洞如何进行攻击利用吗?快来看一看如何利用JWT漏洞进行攻击利用把!https://mp.weixin.qq.com/s/2iBIEGnkiliprsuHyY5Udg...
手机上的APN是什么,该怎么设置
网上说改个APN就可以让网速快几倍,那到底APN是个什么东西,真的能让网速快几倍吗? APN的作用 网络连接基础:APN(接入点名称)是手机连接移动网络的“桥梁”,负责识别运营商网络类型(…...
[bug]langchain agent报错Invalid Format: Missing ‘Action Input:‘ after ‘Action:‘
在学习langchain的agent时候,采用ollama调用本地的deepseek-r1:32b来做一个agent,代码如下: def create_custom_agent():llm ChatOllama(model"deepseek-r1:32b", temperature0.5)memory ConversationBufferWindowMemory(memory…...
blender关联复制与Three.js网格和材质共享验证
blender和three.js小白的学习之路。 最近看到Three.js官网上说,模型合并是一个很好的优化性能的方式,因为渲染2000个物体总要比一次性渲染一个模型要来的慢。很有道理! 但此时就不禁思考一个问题,现有的模型进行合并通过blender…...
Spark宽窄依赖与Join优化:协同划分与非协同划分的底层逻辑
在大数据领域,Spark的性能优化始终是开发者关注的焦点。理解宽依赖(Wide Dependency)和窄依赖(Narrow Dependency)的底层原理,能够帮助我们从根本上优化Join操作的性能。本文将通过这两个核心概念ÿ…...
每日算法-250416
今天我们来探讨两道可以通过贪心算法解决的 LeetCode 题目。 什么是贪心算法? 贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最…...
python爬虫降低IP封禁,python爬虫除了使用代理IP和降低请求频率,还有哪些方法可以应对IP封禁?
文章目录 前言1. 利用 CDN 节点2. 模拟真实用户行为3. 使用 IP 池轮换策略4. 处理 Cookie 和会话信息5. 分布式爬虫 前言 除了使用代理 IP 和降低请求频率,以下这些方法也能应对 IP 封禁: Python 3.13.2安装教程(附安装包)Python…...
NLP高频面试题(四十五)——PPO 算法在 RLHF 中的原理与实现详解
近端策略优化(Proximal Policy Optimization, PPO)算法是强化学习领域的一种新颖且高效的策略优化方法,在近年大规模语言模型的人类反馈强化学习(Reinforcement Learning with Human Feedback, RLHF)中发挥了关键作用。本文将以学术严谨的风格,详细阐述 PPO 算法的原理及…...
bert项目解析
读取csv def read_file(file_path):data []label []with open(file_path, "r", encoding"utf-8") as file:reader csv.reader(file)next(reader) # 跳过标题行for row in reader:if len(row) < 2:print(f"跳过不完整行: {row}")continue…...
ubuntu20.04 Android14编译环境配置
ubuntu 更新和必要安装 sudo apt update sudo apt install git sudo apt install python2-minimal sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 1 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 2 sudo upda…...
lombok requires enabled annotation processing
这个错误信息表明你在使用 Lombok 时,编译器无法正常工作,因为 注解处理器(Annotation Processing) 没有被启用。Lombok 是一个 Java 库,它通过注解处理器在编译时自动生成代码(例如 Getter、Setter、NoArg…...
应用系统中的报表开发成本知多少?
应用系统的开发过程中,报表的业务虽然不算太难,但投入的开发成本可不一定小,因为总会有没完没了的报表要去做,成本的投入不容小觑 下面我们就来分析一下报表开发成本的构成,看看它是多是少 报表的开发成本,…...
STM32F103ZET6移植FATFS文件系统教程(W25Q32)
一、FATFS核心特性 跨平台支持 支持FAT12/FAT16/FAT32格式,兼容Windows文件系统; 采用标准C语言编写,代码量小且支持RTOS。 配置灵活性 通过宏定义实现功能裁剪,例如: FF_FS_READONLY:设为1时禁…...
数据泄露防护系统:全面保护企业信息安全的功能解析
随着信息技术的快速发展,数据泄露事件频发,给企业带来了巨大的经济损失和声誉损害。为了有效应对这一挑战,越来越多的企业开始部署专业的数据泄露防护(DLP)系统。安固软件作为一款领先的数据防泄漏解决方案,…...
【野火模型】利用深度神经网络替代 ELMv1 野火参数化:机制、实现与性能评估
目录 一、ELMv1 野火过程表示法(BASE-Fire)关键机制野火模拟的核心过程 二、采用神经网络模拟野火过程三、总结参考 一、ELMv1 野火过程表示法(BASE-Fire) ELMv1 中的野火模型(称为 BASE-Fire)源自 Commun…...
【WPF】 在WebView2使用echart显示数据
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、NuGet安装WebView2二、代码部分1.xaml中引入webview22.编写html3.在WebView2中加载html4.调用js方法为Echarts赋值 总结 前言 为了实现数据的三维效果&…...
java实现二叉树的前序、中序、后序遍历(递归和非递归方式)以及层级遍历
java实现二叉树的前序、中序、后序遍历以及层级遍历 一、二叉树节点定义二、递归方式1.前序遍历2.中序遍历3.后序遍历 三、非递归方式1.前序遍历2.中序遍历3.后序遍历4.层级遍历5.分层打印 四、测试用例 一、二叉树节点定义 class TreeNode {int val;TreeNode left;TreeNode r…...
学习笔记十三—— 理解 Rust 闭包:从语法到 impl Fn vs Box<dyn Fn>
🧠 理解 Rust 闭包:从语法到 impl Fn vs Box 📚 目录 闭包是什么?和普通函数有什么不同?闭包的语法长什么样?闭包“捕获变量”是什么意思?闭包和所有权的关系Fn、FnMut、FnOnce 三种闭包类型的…...
Linux虚拟机filezilla总是连不上
刚好有两个虚拟机,测试了一下问题所在 从第一个到第二个需要设置什么 image PNG 68.59KB image PNG 134.39KB ChatGLM 从第一个到第二个需要设置开启ssh服务,具体步骤如下: 输入以下命令来启动SSH服务: bash 复制 sud…...
NO.94十六届蓝桥杯备战|图论基础-单源最短路|常规dijkstra|堆优化dijkstra|bellman-ford|spfa(C++)
在图G中,假设 v i v_{i} vi和 v j v_{j} vj为图中的两个顶点,那么 v i v_{i} vi到 v j v_{j} vj路径上所经过边的权值之和就称为带权路径⻓度。 由于 v i v_{i} vi到 v j v_{j} vj的路径可能有多条,将带权路径⻓度最短的那条路径…...
DISCO:利用大型语言模型提取反事实
DISCO: Distilling Counterfactuals with Large Language Models - ACL Anthologyhttps://aclanthology.org/2023.acl-long.302/ 1. 概述 尽管在自然语言处理(NLP)领域针对各种推理任务取得了巨大进展(Wang 等, 2018, 2019a;Xu 等, 2020),但数据集偏差仍然是构建鲁棒模型…...
若依微服务版启动小程序后端
目录标题 本地启动,dev对应 nacos里的 xxx-xxx-dev配置文件 本地启动,dev对应 nacos里的 xxx-xxx-dev配置文件...
C语言 - 深拷贝与浅拷贝详解
深拷贝与浅拷贝详解 在 C 语言编程中,处理指针和动态内存是常见任务。在涉及数据拷贝操作时,我们经常会听到“深拷贝”和“浅拷贝”这两个术语。理解它们之间的区别对于避免程序中的内存错误和数据覆盖问题至关重要。 本文将全面讲解 C 语言中的深拷贝与…...
Serverless集群搭建:Knative
文章目录 Knative搭建1.准备工作安装Kubernetes安装 Istio 2.部署Knative Knative搭建 搭建流程图: 1.准备工作 准备工作 ● 本安装操作中的步骤 bash 适用于 MacOS 或 Linux 环境。对于 Windows,某些命令可能需要调整。 ● 本安装操作假定您具有现有…...
今日行情明日机会——20250416
指数在区间震荡,还需要等突破下跌趋势企稳 2025年4月16日涨停的主要行业方向分析 1. 外贸(9家涨停) 细分领域:跨境物流、纺织出口、供应链服务。代表个股: 五板:泰慕士(纺织服装出口龙头&…...
STM32基础教程——DMA
目录 前言 编辑 技术实现 接线图 代码实现 技术要点 DMA时钟 DMA初始化 DMA数据传输设置 数据改变与显示 实验结果 问题记录 前言 DMA(Direct Memory Access)直接存储器存取,用来提供在外设和存储器 之间或者存储器和存储器之间的高速数据传输。无需…...
Node.js 中文件系统模块(`fs`)的详细总结,包括定义、作用、各种写入方式及使用场景
Node.js 中文件系统模块(fs)的详细总结,包括定义、作用、各种写入方式及使用场景: 🧩 一、fs 模块简介 ✅ 定义 fs(File System)是 Node.js 官方内置模块,用于实现对文件和目录的操…...
MyBatis与MyBatis-Plus:字段自动填充的两种实现方式
目录 1. 使用 MyBatis 拦截器实现字段自动填充 2. 使用 MyBatis-Plus 实现字段自动填充 1. 使用 MyBatis 拦截器实现字段自动填充 实现步骤 创建拦截器 实现 MyBatis 的 Interceptor 接口,通过拦截 MyBatis 执行的 SQL 操作来自动填充公共字段 Intercepts({Signa…...
比特率、码元速率(波特率)的定义、关系及相关计算公式
一、相关定义 (一)比特率 比特率(Bit Rate):单位时间内传输的二进制比特数,是信息传输速率的度量。单位:比特每秒(bit/s,bps)。公式:比特率 传…...
炫云平台全面支持Blender4.4云渲染
随着世界渲染大赛众多优秀作品被大家关注,Blender作为建模渲染一体化的软件,也是众多3D艺术家最常用的软件之一。云渲染自然是提升创作效率必不可少的工作。这篇文章说一下炫云云渲染平台近期对Blender云渲染支持的情况。 首先,炫云客户端已经…...
Python自学第1天:变量,打印,类型转化
突然想学Python了。经过Deepseek的推荐,下载了一个Python3.12安装。安装过程请自行搜索。 乖乖从最基础的学起来,废话不说了,上链接,呃,打错了,上知识点。 变量的定义 # 定义一个整数类型的变量 age 10#…...
Flutter 从零到一
iOS 调试与开发工具指南 真机调试 Xcode run 在控制台获取 Dart VM service URIVSCode 点击 Cmd Shift P 选择 Debug: Attach to Flutter on Device粘贴 the URI 后点击 Enter 对于iOS开发者来说,使用appuploader这样的iOS开发助手可以简化真机调试的准备工作。…...
ocr-身份证正反面识别
在阿里云官网,申请一个token [阿里官方]身份证OCR文字识别_API专区_云市场-阿里云 (aliyun.com) 观察一下post请求body部分json字符串,我们根据这个创建一个java对象 先默认是人像面 public class IdentityBody {public String image;class configure…...
深入解析Spring Boot核心组件及其关键功能
【版本:spring-boot-2.1.3.RELEASE】 深入Spring Boot核心组件 Spring Boot是一个流行的框架,简化了基于Spring的应用程序的开发和部署。它通过自动配置和“开箱即用”的特性,使得开发者可以快速启动和运行应用程序。在Spring Boot中&#x…...
JVM 调优不再难:AI 工具自动生成内存优化方案
在 Java 应用程序的开发与运行过程中,Java 虚拟机(JVM)的性能调优一直是一项极具挑战性的任务,尤其是内存优化方面。不合适的 JVM 内存配置可能会导致应用程序出现性能瓶颈,甚至频繁抛出内存溢出异常,影响业…...
分层式设备控制架构、分布式微服务架构及插件化架构
在现代高端装备制造(如半导体设备、精密自动化系统)中,分层式设备控制架构、分布式微服务架构和插件化架构是提升系统灵活性、实时性和可扩展性的核心技术。以下从设计原理、实现方式及行业应用三个维度展开说明:  1.…...
上门服务 APP 30 亿营收商业模式在乌干达的技术赋能与实践
不久前,非洲乌干达出现黑人女技师提供上门足疗服务的消息引发关注。据了解,当地一次40分钟的上门按摩服务仅需约40元人民币,价格仅为国内同类服务的十分之一。这一现象折射出全球健康服务行业正在经历的数字化转型浪潮。 国内领先的上门服务平…...