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

.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 授权模式。


http://www.kler.cn/a/572120.html

相关文章:

  • SP导入模型设置
  • 机器视觉开发教程——封装Halcon通用模板匹配工具【含免费教程源码】
  • Ubuntu 20.04下ROS项目编译缺少nav_msgs头文件问题
  • Mapmost SDK for WebGL 全新升级——解锁 3DGS 新能力!
  • 【赵渝强老师】监控Redis
  • 搭建laravle 数字产品销售平台 php
  • WPF+WebView 基础
  • 修改hosts文件,修改安全属性,建立自己的DNS
  • leetcode106.相交链表
  • Pytorch构建LeNet进行MNIST识别 #自用
  • es 安装ik分词器
  • Spring Bean 作用域设置为prototype在并发场景下是否是线程安全的
  • 【第14节】C++设计模式(行为模式)-Strategy (策略)模式
  • http 状态码秒记速查(附速记口诀)
  • 【redis】redis持久化
  • 京东Hive SQL面试题实战:APP路径分析场景解析与幽默生存指南
  • 爬虫:一文掌握 Celery 分布式爬虫,及对应实战案例
  • 【应急响应工具教程】一款自动化分析网络安全应急响应工具--FindAll
  • ArcGIS操作:12 矢量shp属性筛选并导出
  • 盛元广通中小型科技创新实验室LIMS系统