- UID
- 665960
- 积分
- 0
- 金币
- 0
- 精华
- 0
- 威望
- 0
- 贡献
- 0
- 阅读权限
- 220
- 注册时间
- 2009-6-29
- 最后登录
- 2026-5-6
- 在线时间
- 0 小时
积极分子
- 金币
- 0
- 阅读权限
- 220
- 精华
- 0
- 威望
- 0
- 贡献
- 0
- 在线时间
- 0 小时
- 注册时间
- 2009-6-29
|
一、先安装必需 NuGet 包
# 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
二、appsettings.json 配置(JWT + 版本)
{
"Jwt": {
"Issuer": "MyServer", // 签发者
"Audience": "MyClient", // 接收者
"SecretKey": "YourLongSecretKeyHere1234567890", // 密钥越长越安全
"ExpiresMinutes": 120 // 过期时间
},
"ApiVersion": {
"DefaultVersion": "1.0"
}
}
三、Program.cs 完整配置
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 =>
{
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 =>
{
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 =>
{
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 =>
{
// 加载所有API版本
var provider = builder.Services.BuildServiceProvider()
.GetRequiredService<IApiVersionDescriptionProvider>();
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<string>()
}
});
// 注释(可选)
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 =>
{
var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
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();
四、JWT 工具类(生成 Token)
创建 JwtHelper.cs
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<string> roles, List<string> permissions)
{
var claims = new List<Claim>
{
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);
}
}
在 Program.cs 注册:
builder.Services.AddScoped<JwtHelper>();
五、API 版本控制使用示例
// V1 版本
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
public class UserController : ControllerBase
{
[HttpGet("info")]
public IActionResult GetV1()
{
return Ok("API V1 用户信息");
}
}
// V2 版本
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("2.0")]
public class UserController : ControllerBase
{
[HttpGet("info")]
public IActionResult GetV2()
{
return Ok("API V2 用户信息");
}
}
六、登录接口(获取 Token)
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[AllowAnonymous] // 无需登录
public class AuthController : ControllerBase
{
private readonly JwtHelper _jwtHelper;
public AuthController(JwtHelper jwtHelper)
{
_jwtHelper = jwtHelper;
}
[HttpPost("login")]
public IActionResult Login(string username, string password)
{
// 这里替换成真实数据库校验
if (username == "admin" && password == "123456")
{
var token = _jwtHelper.GenerateToken(
userId: "1001",
userName: "admin",
roles: new List<string> { "Admin" },
permissions: new List<string> { "User:List", "User:Add", "User:Delete" }
);
return Ok(new { Token = token });
}
return Unauthorized("账号密码错误");
}
}
七、权限设计
1. 权限设计思想
- 基于 RBAC:用户 → 角色 → 权限
- 权限粒度:功能权限字符串,如
User:List、Order:Create
- 校验方式:自定义权限过滤器
2. 自定义权限注解
[AttributeUsage(AttributeTargets.Method)]
public class PermissionAttribute : Attribute
{
public string Code { get; }
public PermissionAttribute(string code)
{
Code = code;
}
}
3. 权限验证过滤器
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 => m is AllowAnonymousAttribute))
return;
// 获取当前方法需要的权限
var permission = context.ActionDescriptor.EndpointMetadata
.OfType<PermissionAttribute>()
.FirstOrDefault();
if (permission == null) return;
// 获取用户拥有的权限
var userPermissions = context.HttpContext.User.Claims
.Where(c => c.Type == "Permission")
.Select(c => c.Value)
.ToList();
// 校验
if (!userPermissions.Contains(permission.Code))
{
context.Result = new ForbidResult();
}
}
}
在 Program.cs 注册全局过滤器:
builder.Services.AddMvc(options =>
{
options.Filters.Add<PermissionFilter>();
});
八、权限 + 版本 + 授权的 API 示例
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[Authorize] // 需要登录
public class UserController : ControllerBase
{
// 需要权限:User:List
[HttpGet]
[Permission("User:List")]
public IActionResult GetList()
{
return Ok("用户列表");
}
// 需要权限:User:Add
[HttpPost]
[Permission("User:Add")]
public IActionResult Add()
{
return Ok("添加成功");
}
// 需要权限:User:Delete
[HttpDelete("{id}")]
[Permission("User:Delete")]
public IActionResult Delete(int id)
{
return Ok("删除成功");
}
}
九、Swagger 使用效果
运行后打开:https://localhost:5001/swagger
- 自动分版本:v1 /v2
- 右上角有 Authorize 按钮
- 输入:
Bearer 你的token
- 即可访问需要登录 / 权限的接口
十、总结
- 调用
/api/v1/Auth/login 获取 Token
- Swagger 点击 Authorize 输入
Bearer token
- 访问不同版本 API
- 系统自动校验:登录 → 角色 → 权限
- 权限不满足直接返回 403
来源:https://www.cnblogs.com/chuansheng/p/19913597 |
|