当前位置: 首页 > news >正文

.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'

接口输出信息:

License/types响应信息

  • 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"}
}'

接口输出信息:

License/activate响应信息

可以看出,上面两个白名单 中的接口均可访问,接下来我们再次访问默认的天气接口 /WeatherForecast,验证是否被授权激活。

  • WeatherForecast

再次执行同样的命令:

curl -X 'GET' \'http://localhost:5089/WeatherForecast' \-H 'accept: text/plain'

输出信息:

WeatherForecast接口授权响应

通过我们上面两次的接口测试验证,默认天气接口已经正常响应数据,说明该应用程序已经使用了 License 授权模式。

相关文章:

.net8 使用 license 证书授权案例解析

创建 webapi 项目 使用 .NET CLI 创建一个 ASP.NET Core Web API 应用&#xff0c;并添加指定的 NuGet 包&#xff0c;可以按照以下步骤操作&#xff1a; 创建 ASP.NET Core Web API 项目&#xff1a; dotnet new webapi -n WebAppLicense cd WebAppLicense添加 Standard.Li…...

golang的io

https://www.bilibili.com/video/BV1gx4y1r7xb 1. 原生io包 io包是Go语言标准库中底层的I/O接口层&#xff0c;定义了通用的读写规则和错误处理逻辑。每次读写都是直接调用底层系统 I/O&#xff0c;每次读取1字节&#xff0c;系统调用次数多。适用于小数据量、实时性要求高。i…...

全向广播扬声器在油气田中的关键应用 全方位守护安全

油气田作为高风险作业场所&#xff0c;安全生产始终是重中之重。在紧急情况下&#xff0c;如何快速、有效地传达信息&#xff0c;确保人员安全撤离&#xff0c;是油气田安全管理的关键环节。全向广播扬声器凭借其全方位覆盖、高音质输出和强大的环境适应性&#xff0c;成为油气…...

76.读取计时器运行时间 C#例子 WPF例子

TimerManager&#xff1a;一个增强的定时器类&#xff0c;带时间管理功能 在使用定时器时&#xff0c;我们常常需要知道定时器的运行状态&#xff0c;比如它已经运行了多久&#xff0c;或者还剩下多少时间。然而&#xff0c;.NET 的 System.Timers.Timer 类本身并没有直接提供…...

嵌入式开发:傅里叶变换(5):基于STM32,实现CMSIS中的DSP库

目录 步骤 1&#xff1a;准备工作 步骤 2&#xff1a;创建 Keil 项目&#xff0c;并配置工程 步骤 3&#xff1a;在MDK工程上添加 CMSIS-DSP 库 步骤 5&#xff1a;编写代码 步骤 6&#xff1a;配置时钟和优化 步骤 7&#xff1a;调试与验证 步骤 8&#xff1a;优化和调…...

探秘基带算法:从原理到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 总结&#xff1a;CRC校…...

MySQL——DQL、多表设计

目录 一、DQL 1.基本查询 2.条件查询 3.分组查询 4.排序查询 5.分页查询 二、多表设计 1.一对多 2.一对一 3.多对多 一、DQL 1.基本查询 注意&#xff1a; *号代表查询所有字段&#xff0c;在实际开发中尽量少用&#xff08;不直观、影响效率&#xff09; 2.条件查询…...

XML 编辑器:全面指南与最佳实践

XML 编辑器:全面指南与最佳实践 引言 XML(可扩展标记语言)编辑器是处理XML文件的关键工具,对于开发人员、系统管理员以及任何需要处理XML数据的人来说至关重要。本文将全面介绍XML编辑器的概念、功能、选择标准以及最佳实践,旨在帮助读者了解如何选择和使用合适的XML编辑…...

【USRP】NVIDIA Sionna:用于 6G 物理层研究的开源库

目录 Sionna&#xff1a;用于 6G 物理层研究的开源库主要特点实现6G研究的民主化支持 5G、6G 等模块化、可扩展、可伸缩快速启动您的研究 好处原生人工智能支持综合研究平台开放生态系统 安装笔记使用 pip 安装基于Docker的安装从源代码安装“你好世界&#xff01;”探索锡奥纳…...

DeepSeek开源周Day6:DeepSeek V3、R1 推理系统深度解析,技术突破与行业启示

DeepSeek 在开源周第六天再次发文&#xff0c;中文原文、官方号在知乎 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联动

一、前言 有一个需求&#xff0c;想实现从页面上传一个excel文件&#xff0c;点击提交&#xff0c;就转发给forma模块&#xff0c;然后用户在forma模块里&#xff0c;确认下自动填写的信息是否正确&#xff0c;正确的话就点击保存&#xff0c;存入数据库&#xff1b;不正确的话…...

《大语言模型的原理发展与应用》:此文为AI自动生成

《大语言模型的原理发展与应用》&#xff1a;此文为AI自动生成 一、引言&#xff1a;大语言模型&#xff0c;AI 时代的 “新引擎” 在当今数字化浪潮中&#xff0c;大语言模型宛如一颗璀璨的明星&#xff0c;照亮了人工智能发展的道路&#xff0c;成为推动各领域变革的核心驱…...

生态安全相关

概念&#xff1a;生态安全指一个国家具有支撑国家生存发展的较为完整、不受威胁的生态系统&#xff0c;以及应对内外重大生态问题的能力。 &#xff08;1&#xff09;国外生态安全的研究进展 国际上对生态安全的研究是从“环境”与“安全”之间的关系展开的。开始的阶段&#x…...

DeepSeek-R1国产化系统gpu驱动+cuda+ollama+webui可视化离线私有化部署

1.概述 网上大部分教程都是在线部署&#xff0c;完全离线私有化部署的文章不多&#xff0c;本文介绍从GPU驱动、cuda、ollama、deepseek模型和open webui等完全离线安装几个方面&#xff0c;让小白0基础也可以私有化部署大模型deepseek-R1。 我使用的设备是银河麒麟V10操作系统…...

数据集/API 笔记:新加坡风速 API

data.gov.sg 数据范围&#xff1a;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

本节目标&#xff1a; stack的介绍与使用queue的介绍与使用priority_queue的介绍与使用容器适配器模拟实现与结语 1 stack&#xff08;堆&#xff09;的介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;只能从容器的一端进行元素的插…...

算法 并查集

目录 前言 一 并查集的思路 二 并查集的代码分析 三 实操我们的代码 四 并查集的代码优化 总结 前言 并查集主要是用来求解集合问题的&#xff0c;用来查找集合还有就是合并集合&#xff0c;可以把这个运用到最小生成树里面 一 并查集的思路 1 并查集的相关的操作…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...