.net8 使用 license 证书授权案例解析
创建 webapi 项目
使用 .NET CLI 创建一个 ASP.NET Core Web API 应用,并添加指定的 NuGet 包,可以按照以下步骤操作:
- 创建
ASP.NET Core Web API项目:
dotnet new webapi -n WebAppLicense
cd WebAppLicense
- 添加
Standard.Licensing包:
dotnet add package Standard.Licensing --version 1.2.1
- 添加
Swashbuckle.AspNetCore包:
dotnet add package Swashbuckle.AspNetCore --version 7.3.1
- 验证
csproj文件: 打开WebAppLicense.csproj文件,确保以下内容已添加:
<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings></PropertyGroup><ItemGroup><PackageReference Include="Standard.Licensing" Version="1.2.1" /><PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.1" /></ItemGroup></Project>
到此处可以启动运行项目,目的是验证默认环境是否正确,确保进入下一环节的正常运行。
改造项目使用 license 授权
项目结构
依照如下项目结构改造,信息如下:

修改 Program.cs 文件
修改 Program.cs 文件,代码如下:
using System.Net.Mime;
using WebAppLicense.Services;
using WebAppLicense.Environments;
using WebAppLicense.Middlewares;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();// 添加服务到容器
builder.Services.AddSingleton<ILicenseService, LicenseService>();var app = builder.Build();// 使用自定义许可证验证中间件
// app.UseLicenseValidation();// 在应用启动时验证许可证(此处可封装扩展中间件UseLicenseValidation)
#region 在应用启动时验证许可证
// 定义响应报文类型
string contentType = $"{MediaTypeNames.Text.Plain};charset=utf-8";
// 定义要跳过的路由路径
List<string> skipPaths = ["/api/License/activate", "/api/License/types"];app.Use(async (context, next) =>
{HttpContext httpContext = context;var pathString = httpContext.Request.Path;// 检查当前请求路径是否与 Swagger 相关if (pathString.StartsWithSegments("/swagger")|| pathString.StartsWithSegments("/scalar")|| pathString.StartsWithSegments("/favicon.ico")){await next(httpContext);return;}// 检查当前请求路径是否在跳过列表中if (skipPaths.Contains(pathString)){await next(httpContext);return;}// 假设许可证内容存储在环境变量中var licenseContentBase64 = Environment.GetEnvironmentVariable(LicenseEnv.LICENSE_CONTENT_SECRET);if (string.IsNullOrEmpty(licenseContentBase64)){httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;httpContext.Response.ContentType = contentType;await httpContext.Response.WriteAsync("许可证未提供。");return;}var licenseService = httpContext.RequestServices.GetRequiredService<ILicenseService>();var (isValid, msg) = licenseService.ValidateLicense(licenseContentBase64);if (!isValid){httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;httpContext.Response.ContentType = contentType;await httpContext.Response.WriteAsync($"许可证无效。{msg}");return;}// 如果许可证有效,继续处理请求await next(httpContext);
});
#endregion// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseAuthorization();
app.MapControllers();
await app.RunAsync();
项目相关接口
- 默认天气接口,
WeatherForecastController
using Microsoft.AspNetCore.Mvc;
using WebAppLicense.Model.ViewModel;namespace WebAppLicense.Controllers;[ApiController]
[Route("[controller]")]
public class WeatherForecastController(ILogger<WeatherForecastController> logger) : ControllerBase
{private static readonly string[] Summaries =["Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];[HttpGet(Name = "GetWeatherForecast")]public IEnumerable<WeatherForecast> Get(){return Enumerable.Range(1, 3).Select(index => new WeatherForecast{Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),TemperatureC = Random.Shared.Next(-20, 55),Summary = Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();}
}
- 新增
license接口,LicenseController
using Microsoft.AspNetCore.Mvc;
using WebAppLicense.Model.ViewModel;
using WebAppLicense.Services;namespace WebAppLicense.Controllers;[Route("api/[controller]")]
[ApiController]
public class LicenseController(ILicenseService licenseService) : ControllerBase
{// 提供的 license 授权类型[HttpGet("types")]public Dictionary<string, int> GetLicenseTypes(){var licenseTypes = licenseService.GetLicenseTypes();return licenseTypes;}// 激活 license 授权[HttpPost("activate")]public async Task<IActionResult> ActivateLicense([FromBody] LicenseActivationRequest request){var licenseContent = await licenseService.GenerateLicenseAsync(request);return Ok(new {request.LicenseType,License = licenseContent,});}
}
ILicenseService服务
using WebAppLicense.Model.ViewModel;namespace WebAppLicense.Services;public interface ILicenseService
{Dictionary<string, int> GetLicenseTypes();ValueTask<string> GenerateLicenseAsync(LicenseActivationRequest request, bool isSaveLicenseFile = false);(bool state, string msg) ValidateLicense(string licenseContentBase64);
}
项目基本信息解释到此,其他详细信息,请查看 WebAppLicense 项目。
授权测试
启动项目,显示页面信息如下:

项目相关接口信息说明:
WeatherForecast
默认的天气接口,用于测试项目是否使用授权模式,如果为授权则提示相应的信息。
License
新增的接口,分别用于提供授权类型和授权激活(通过密钥方式),因此这两个接口被设置为 白名单。
测试流程如下:
首先访问接口 /WeatherForecast,执行如下命令,
curl -X 'GET' \'http://localhost:5089/WeatherForecast' \-H 'accept: text/plain'
输出信息:

从接口返回信息,可以看出该接口在未获得授权 license 的时候被请求。
此时我们使用授权激活接口,通过密钥方式激活授权 license,然后再次访问接口 /WeatherForecast,查看接口响应信息,验证接口是否已经授权。
api/License/types
访问接口,执行如下命令:
curl -X 'GET' \'http://localhost:5089/api/License/types' \-H 'accept: text/plain'
接口输出信息:

api/License/activate
访问接口,执行如下命令:
curl -X 'POST' \'http://localhost:5089/api/License/activate' \-H 'accept: */*' \-H 'Content-Type: application/json' \-d '{"licenseType": "trial","utilization": 5,"passPhrase": "123456","expirationDate": "2025-03-03T13:30:02.644Z","userName": "jeff","email": "jeff@qq.com","productFeatures": {"additionalProp1": "yes","additionalProp2": "no","additionalProp3": "yes"}
}'
接口输出信息:

可以看出,上面两个白名单 中的接口均可访问,接下来我们再次访问默认的天气接口 /WeatherForecast,验证是否被授权激活。
WeatherForecast
再次执行同样的命令:
curl -X 'GET' \'http://localhost:5089/WeatherForecast' \-H 'accept: text/plain'
输出信息:

通过我们上面两次的接口测试验证,默认天气接口已经正常响应数据,说明该应用程序已经使用了 License 授权模式。
相关文章:
.net8 使用 license 证书授权案例解析
创建 webapi 项目 使用 .NET CLI 创建一个 ASP.NET Core Web API 应用,并添加指定的 NuGet 包,可以按照以下步骤操作: 创建 ASP.NET Core Web API 项目: dotnet new webapi -n WebAppLicense cd WebAppLicense添加 Standard.Li…...
golang的io
https://www.bilibili.com/video/BV1gx4y1r7xb 1. 原生io包 io包是Go语言标准库中底层的I/O接口层,定义了通用的读写规则和错误处理逻辑。每次读写都是直接调用底层系统 I/O,每次读取1字节,系统调用次数多。适用于小数据量、实时性要求高。i…...
全向广播扬声器在油气田中的关键应用 全方位守护安全
油气田作为高风险作业场所,安全生产始终是重中之重。在紧急情况下,如何快速、有效地传达信息,确保人员安全撤离,是油气田安全管理的关键环节。全向广播扬声器凭借其全方位覆盖、高音质输出和强大的环境适应性,成为油气…...
76.读取计时器运行时间 C#例子 WPF例子
TimerManager:一个增强的定时器类,带时间管理功能 在使用定时器时,我们常常需要知道定时器的运行状态,比如它已经运行了多久,或者还剩下多少时间。然而,.NET 的 System.Timers.Timer 类本身并没有直接提供…...
嵌入式开发:傅里叶变换(5):基于STM32,实现CMSIS中的DSP库
目录 步骤 1:准备工作 步骤 2:创建 Keil 项目,并配置工程 步骤 3:在MDK工程上添加 CMSIS-DSP 库 步骤 5:编写代码 步骤 6:配置时钟和优化 步骤 7:调试与验证 步骤 8:优化和调…...
探秘基带算法:从原理到5G时代的通信变革【六】CRC 校验
文章目录 2.5 CRC 校验2.5.1 前言2.5.2 CRC算法简介2.5.3 CRC计算的详细过程2.5.4 CRC校验的两种方法详解**分离比较法****整体运算法****不同位出错与余数的关系****总结** 2.5.5 CRC计算的C实现及工具介绍**C实现CRC计算****CRC计算工具推荐** **2.5.6 总结:CRC校…...
MySQL——DQL、多表设计
目录 一、DQL 1.基本查询 2.条件查询 3.分组查询 4.排序查询 5.分页查询 二、多表设计 1.一对多 2.一对一 3.多对多 一、DQL 1.基本查询 注意: *号代表查询所有字段,在实际开发中尽量少用(不直观、影响效率) 2.条件查询…...
XML 编辑器:全面指南与最佳实践
XML 编辑器:全面指南与最佳实践 引言 XML(可扩展标记语言)编辑器是处理XML文件的关键工具,对于开发人员、系统管理员以及任何需要处理XML数据的人来说至关重要。本文将全面介绍XML编辑器的概念、功能、选择标准以及最佳实践,旨在帮助读者了解如何选择和使用合适的XML编辑…...
【USRP】NVIDIA Sionna:用于 6G 物理层研究的开源库
目录 Sionna:用于 6G 物理层研究的开源库主要特点实现6G研究的民主化支持 5G、6G 等模块化、可扩展、可伸缩快速启动您的研究 好处原生人工智能支持综合研究平台开放生态系统 安装笔记使用 pip 安装基于Docker的安装从源代码安装“你好世界!”探索锡奥纳…...
DeepSeek开源周Day6:DeepSeek V3、R1 推理系统深度解析,技术突破与行业启示
DeepSeek 在开源周第六天再次发文,中文原文、官方号在知乎 DeepSeek - 知乎DeepSeek-V3 / R1 推理系统概览 - 知乎deepseek-ai/open-infra-index: Production-tested AI infrastructure tools for efficient AGI development and community-driven innovation 引言 …...
intra-mart实现logicDesigner与forma联动
一、前言 有一个需求,想实现从页面上传一个excel文件,点击提交,就转发给forma模块,然后用户在forma模块里,确认下自动填写的信息是否正确,正确的话就点击保存,存入数据库;不正确的话…...
《大语言模型的原理发展与应用》:此文为AI自动生成
《大语言模型的原理发展与应用》:此文为AI自动生成 一、引言:大语言模型,AI 时代的 “新引擎” 在当今数字化浪潮中,大语言模型宛如一颗璀璨的明星,照亮了人工智能发展的道路,成为推动各领域变革的核心驱…...
生态安全相关
概念:生态安全指一个国家具有支撑国家生存发展的较为完整、不受威胁的生态系统,以及应对内外重大生态问题的能力。 (1)国外生态安全的研究进展 国际上对生态安全的研究是从“环境”与“安全”之间的关系展开的。开始的阶段&#x…...
DeepSeek-R1国产化系统gpu驱动+cuda+ollama+webui可视化离线私有化部署
1.概述 网上大部分教程都是在线部署,完全离线私有化部署的文章不多,本文介绍从GPU驱动、cuda、ollama、deepseek模型和open webui等完全离线安装几个方面,让小白0基础也可以私有化部署大模型deepseek-R1。 我使用的设备是银河麒麟V10操作系统…...
数据集/API 笔记:新加坡风速 API
data.gov.sg 数据范围:2016年12月 - 2025年3月 API 查询方式 curl --request GET \--url https://api-open.data.gov.sg/v2/real-time/api/wind-speedcurl --request GET \--url "https://api-open.data.gov.sg/v2/real-time/api/wind-speed?date2024-07-16…...
transformer架构解析{掩码,(自)注意力机制,多头(自)注意力机制}(含代码)-3
目录 前言 掩码张量 什么是掩码张量 掩码张量的作用 生成掩码张量实现 注意力机制 学习目标 注意力计算规则 注意力和自注意力 注意力机制 注意力机制计算规则的代码实现 多头注意力机制 学习目标 什么是多头注意力机制 多头注意力计算机制的作用 多头注意力机…...
【C++】switch 语句编译报错:error: jump to case label
/home/share/mcrockit_3588/prj_linux/../source/rkvpss.cpp: In member function ‘virtual u32 CRkVpss::Control(u32, void*, u32)’: /home/share/mcrockit_3588/prj_linux/../source/rkvpss.cpp:242:8: error: jump to case label242 | case emRkComCmd_DBG_SaveInput:|…...
linux中使用firewall命令操作端口
一、开放端口 1. 开放一个端口 sudo firewall-cmd --zonepublic --add-port8443/tcp --permanent sudo firewall-cmd --reload 2. 开放一组连续端口 sudo firewall-cmd --zonepublic --add-port100-500/tcp --permanent sudo firewall-cmd --reload 3. 一次开放多个不连续…...
C++第六节:stack和queue
本节目标: stack的介绍与使用queue的介绍与使用priority_queue的介绍与使用容器适配器模拟实现与结语 1 stack(堆)的介绍 stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,只能从容器的一端进行元素的插…...
算法 并查集
目录 前言 一 并查集的思路 二 并查集的代码分析 三 实操我们的代码 四 并查集的代码优化 总结 前言 并查集主要是用来求解集合问题的,用来查找集合还有就是合并集合,可以把这个运用到最小生成树里面 一 并查集的思路 1 并查集的相关的操作…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
vxe-table vue 表格复选框多选数据,实现快捷键 Shift 批量选择功能
vxe-table vue 表格复选框多选数据,实现快捷键 Shift 批量选择功能 查看官网:https://vxetable.cn 效果 代码 通过 checkbox-config.isShift 启用批量选中,启用后按住快捷键和鼠标批量选取 <template><div><vxe-grid v-bind"gri…...
