融方于圆 發表於 2026-4-25 10:43:00

.NET 集成 Swagger、API 版本控制 、JWT 授权、权限设计

<h2>一、先安装必需 NuGet 包</h2>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code># API版本控制
Install-Package Microsoft.AspNetCore.Mvc.Versioning
Install-Package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer

# JWT
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

# Swagger
Install-Package Swashbuckle.AspNetCore
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>二、appsettings.json 配置(JWT + 版本)</h2>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<div>json</div>
<div>&nbsp;</div>
</div>
<div>
<pre><code>{
"Jwt": {
    "Issuer": "MyServer",      // 签发者
    "Audience": "MyClient",      // 接收者
    "SecretKey": "YourLongSecretKeyHere1234567890", // 密钥越长越安全
    "ExpiresMinutes": 120      // 过期时间
},
"ApiVersion": {
    "DefaultVersion": "1.0"
}
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>三、Program.cs 完整配置</h2>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 1. 添加控制器
builder.Services.AddControllers();

// ==============================================
// 2. 配置 API 版本控制
// ==============================================
builder.Services.AddApiVersioning(options =&gt;
{
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.ReportApiVersions = true; // 返回头显示支持的版本
    options.ApiVersionReader = ApiVersionReader.Combine(
      new UrlSegmentApiVersionReader(),      // /api/v1/xx
      new HeaderApiVersionReader("api-version"), // Header: api-version:1.0
      new QueryStringApiVersionReader("v")   // ?v=1.0
    );
});

builder.Services.AddVersionedApiExplorer(options =&gt;
{
    options.GroupNameFormat = "'v'VVV"; // v1, v1.0
    options.SubstituteApiVersionInUrl = true;
});

// ==============================================
// 3. 配置 JWT 授权
// ==============================================
var jwtSection = builder.Configuration.GetSection("Jwt");
var secretKey = Encoding.UTF8.GetBytes(jwtSection["SecretKey"]!);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =&gt;
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
      ValidateIssuer = true,
      ValidateAudience = true,
      ValidateLifetime = true,
      ValidateIssuerSigningKey = true,
      ValidIssuer = jwtSection["Issuer"],
      ValidAudience = jwtSection["Audience"],
      IssuerSigningKey = new SymmetricSecurityKey(secretKey),
      ClockSkew = TimeSpan.Zero // 不允许时间误差
    };
});

// ==============================================
// 4. 配置 Swagger + 版本 + JWT
// ==============================================
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =&gt;
{
    // 加载所有API版本
    var provider = builder.Services.BuildServiceProvider()
      .GetRequiredService&lt;IApiVersionDescriptionProvider&gt;();

    foreach (var description in provider.ApiVersionDescriptions)
    {
      options.SwaggerDoc(description.GroupName, new Microsoft.OpenApi.Models.OpenApiInfo
      {
            Title = $"API {description.GroupName}",
            Version = description.GroupName,
            Description = "带版本 + JWT授权的API文档"
      });
    }

    // Swagger 支持 JWT 认证
    options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
    {
      Name = "Authorization",
      Type = Microsoft.OpenApi.SecuritySchemeType.Http,
      Scheme = "Bearer",
      BearerFormat = "JWT",
      In = Microsoft.OpenApi.ParameterLocation.Header,
      Description = "输入格式:Bearer {token}"
    });

    options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
    {
      {
            new Microsoft.OpenApi.Models.OpenApiSecurityScheme
            {
                Reference = new Microsoft.OpenApi.Models.OpenApiReference
                {
                  Type = Microsoft.OpenApi.ReferenceType.SecurityScheme,
                  Id = "Bearer"
                }
            },
            Array.Empty&lt;string&gt;()
      }
    });

    // 注释(可选)
    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    options.IncludeXmlComments(xmlPath, true);
});

var app = builder.Build();

// 启用Swagger版本分组
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(options =&gt;
    {
      var provider = app.Services.GetRequiredService&lt;IApiVersionDescriptionProvider&gt;();
      foreach (var description in provider.ApiVersionDescriptions)
      {
            options.SwaggerEndpoint(
                $"/swagger/{description.GroupName}/swagger.json",
                $"API {description.GroupName}"
            );
      }
    });
}

app.UseHttpsRedirection();
app.UseAuthentication(); // 必须在 Authorization 之前
app.UseAuthorization();
app.MapControllers();
app.Run();
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>四、JWT 工具类(生成 Token)</h2>
<div>&nbsp;</div>
<div>创建 <code>JwtHelper.cs</code></div>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace YourNamespace;

public class JwtHelper
{
    private readonly IConfiguration _config;

    public JwtHelper(IConfiguration config)
    {
      _config = config;
    }

    // 生成JWT Token(可传入用户ID、角色、权限)
    public string GenerateToken(string userId, string userName, List&lt;string&gt; roles, List&lt;string&gt; permissions)
    {
      var claims = new List&lt;Claim&gt;
      {
            new Claim(ClaimTypes.NameIdentifier, userId),
            new Claim(ClaimTypes.Name, userName)
      };

      // 添加角色
      foreach (var role in roles)
            claims.Add(new Claim(ClaimTypes.Role, role));

      // 添加权限
      foreach (var p in permissions)
            claims.Add(new Claim("Permission", p));

      var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:SecretKey"]!));
      var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

      var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(_config["Jwt:ExpiresMinutes"])),
            signingCredentials: creds
      );

      return new JwtSecurityTokenHandler().WriteToken(token);
    }
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<div>在 Program.cs 注册:</div>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>builder.Services.AddScoped&lt;JwtHelper&gt;();
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>五、API 版本控制使用示例</h2>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>// V1 版本

")]

public class UserController : ControllerBase
{
   
    public IActionResult GetV1()
    {
      return Ok("API V1 用户信息");
    }
}

// V2 版本

")]

public class UserController : ControllerBase
{
   
    public IActionResult GetV2()
    {
      return Ok("API V2 用户信息");
    }
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>六、登录接口(获取 Token)</h2>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>
")]

// 无需登录
public class AuthController : ControllerBase
{
    private readonly JwtHelper _jwtHelper;

    public AuthController(JwtHelper jwtHelper)
    {
      _jwtHelper = jwtHelper;
    }

   
    public IActionResult Login(string username, string password)
    {
      // 这里替换成真实数据库校验
      if (username == "admin" &amp;&amp; password == "123456")
      {
            var token = _jwtHelper.GenerateToken(
                userId: "1001",
                userName: "admin",
                roles: new List&lt;string&gt; { "Admin" },
                permissions: new List&lt;string&gt; { "User:List", "User:Add", "User:Delete" }
            );

            return Ok(new { Token = token });
      }
      return Unauthorized("账号密码错误");
    }
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>七、权限设计</h2>
<div>&nbsp;</div>
<h3>1. 权限设计思想</h3>
<div>&nbsp;</div>
<ul>
<li>基于 RBAC:用户 → 角色 → 权限</li>
<li>权限粒度:功能权限字符串,如 <code>User:List</code>、<code>Order:Create</code></li>
<li>校验方式:自定义权限过滤器</li>
</ul>
<div>&nbsp;</div>
<h3>2. 自定义权限注解</h3>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>
public class PermissionAttribute : Attribute
{
    public string Code { get; }

    public PermissionAttribute(string code)
    {
      Code = code;
    }
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<h3>3. 权限验证过滤器</h3>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace YourNamespace;

public class PermissionFilter : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
      // 跳过匿名接口
      if (context.ActionDescriptor.EndpointMetadata.Any(m =&gt; m is AllowAnonymousAttribute))
            return;

      // 获取当前方法需要的权限
      var permission = context.ActionDescriptor.EndpointMetadata
            .OfType&lt;PermissionAttribute&gt;()
            .FirstOrDefault();

      if (permission == null) return;

      // 获取用户拥有的权限
      var userPermissions = context.HttpContext.User.Claims
            .Where(c =&gt; c.Type == "Permission")
            .Select(c =&gt; c.Value)
            .ToList();

      // 校验
      if (!userPermissions.Contains(permission.Code))
      {
            context.Result = new ForbidResult();
      }
    }
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<div>在 Program.cs 注册全局过滤器:</div>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>builder.Services.AddMvc(options =&gt;
{
    options.Filters.Add&lt;PermissionFilter&gt;();
});
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>八、权限 + 版本 + 授权的 API 示例</h2>
<div>&nbsp;</div>
<div>
<div dir="ltr">
<div>
<pre><code>
")]

// 需要登录
public class UserController : ControllerBase
{
    // 需要权限:User:List
   
   
    public IActionResult GetList()
    {
      return Ok("用户列表");
    }

    // 需要权限:User:Add
   
   
    public IActionResult Add()
    {
      return Ok("添加成功");
    }

    // 需要权限:User:Delete
   
   
    public IActionResult Delete(int id)
    {
      return Ok("删除成功");
    }
}
</code></pre>
</div>
<div>&nbsp;</div>
</div>
</div>
<hr>
<div>&nbsp;</div>
<h2>九、Swagger 使用效果</h2>
<div>&nbsp;</div>
<div>运行后打开:<code>https://localhost:5001/swagger</code></div>
<div>&nbsp;</div>
<ul>
<li>自动分版本:v1 /v2</li>
<li>右上角有 Authorize 按钮</li>
<li>输入:<code>Bearer 你的token</code></li>
<li>即可访问需要登录 / 权限的接口</li>
</ul>
<div>&nbsp;</div>
<hr>
<div>&nbsp;</div>
<h2>十、总结</h2>
<div>&nbsp;</div>
<ol>
<li>调用 <code>/api/v1/Auth/login</code> 获取 Token</li>
<li>Swagger 点击 Authorize 输入 <code>Bearer token</code></li>
<li>访问不同版本 API</li>
<li>系统自动校验:登录 → 角色 → 权限</li>
<li>权限不满足直接返回 403</li>
</ol><br><br>
来源:https://www.cnblogs.com/chuansheng/p/19913597
頁: [1]
查看完整版本: .NET 集成 Swagger、API 版本控制 、JWT 授权、权限设计