闽公网安备 35020302035485号
我们开发的API必须做鉴权和授权操作,否则,就成了裸跑了,那对于系统来说是很危险的。总体来说,一般的WebAPI和MinimalAPI鉴权的过程都是差不多的,但是也有微小的差异。今天我们就来详细说一下,内容很简单,大家有了基础可以随意去扩展。
1、第一个项目:PatrickLiu.Net6API.AuthenticationCenter,用于提供获取 Token 接口。
// 堆代码 duidaima.com
using PatrickLiu.Net6API.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.Configure<JWTTokenOption>(builder.Configuration.GetSection("JWTTokenOption"));
builder.Services.AddTransient<IJWTService, JWTService>();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.MapControllers();
app.Run();
(2)、AuthenticationController 源码如下:using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using PatrickLiu.Net6API.Extensions;
namespace PatrickLiu.Net6API.AuthenticationCenter.Controllers
{
[ApiController]
[Route("api/[controller]/[action]")]
public class AuthenticationController : ControllerBase
{
private readonly IJWTService _jWTService;
/// <summary>
/// 实例化。
/// </summary>
/// <param name="jWTService">注入服务。</param>
public AuthenticationController(IJWTService jWTService)
{
_jWTService = jWTService;
}
/// <summary>
/// 堆代码 duidaima.com
/// 根据用户名和密码获取 Token。
/// </summary>
/// <param name="userName">用户名。</param>
/// <param name="password">密码。</param>
/// <returns></returns>
[HttpPost]
public string Login(string userName, string password)
{
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
if (string.Compare(userName, "PatrickLiu", true) == 0 && string.Compare(password, "liulei123456", true) == 0)
{
string token = _jWTService.GetToken(userName, password);
return JsonConvert.SerializeObject(new
{
Result = true,
Token = token
});
}
}
return string.Empty;
}
}
}
(3)、appsettings.json 配置文件源码如下,红色字体要注意:{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JWTTokenOption": {
"Audience": "PatrickLiu.com",
"Issuer": "PatrickLiu.com",
"SecurityKey": "12333456677655ffrrffff"
}
}
2、还有一个公共项目,用于存放公共类型。项目类型:PatrickLiu.Net6API.Extensions,项目类型:Net 6.0类库。
namespace PatrickLiu.Net6API.Extensions
{
/// <summary>
/// 提供 Token 的服务。
/// </summary>
public interface IJWTService
{
/// <summary>
/// 获取 Token。
/// </summary>
/// <param name="userName">用户名</param>
/// <param name="password">密码</param>
/// <returns></returns>
string GetToken(string userName,string password);
}
}
(2)、JWTService 源码如下: using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
namespace PatrickLiu.Net6API.Extensions
{
/// <summary>
/// 提供 Token 服务的实现。
/// </summary>
public sealed class JWTService : IJWTService
{
private readonly IOptionsMonitor<JWTTokenOption> _option;
/// <summary>
/// 实例化。
/// </summary>
/// <param name="option">注入选项。</param>
public JWTService(IOptionsMonitor<JWTTokenOption> option)
{
_option = option;
}
/// <summary>
/// 获取 Token。
/// </summary>
/// <param name="userName">用户名。</param>
/// <param name="password">密码</param>
/// <returns></returns>
public string GetToken(string userName, string password)
{
#region 有效载荷
var claims = new[] {
new Claim(ClaimTypes.Name, userName),
new Claim("NickName",userName),
new Claim(ClaimTypes.Role,"Administrator"),
new Claim("Password",password),
};
#endregion
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_option.CurrentValue.SecurityKey!));
SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
JwtSecurityToken token = new JwtSecurityToken(
issuer: _option.CurrentValue.Issuer!,
audience: _option.CurrentValue.Audience!,
claims: claims,
expires: DateTime.Now.AddMinutes(5),
signingCredentials: signingCredentials
);
string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
return returnToken;
}
}
}
(3)、JWTTokenOption 源码如下:namespace PatrickLiu.Net6API.Extensions
{
/// <summary>
/// 用于接受配置数据实体类型。
/// </summary>
public sealed class JWTTokenOption
{
/// <summary>
/// 获取或者设置接受者。
/// </summary>
public string? Audience { get; set; }
/// <summary>
/// 获取或者设置加密 key。
/// </summary>
public string? SecurityKey { get; set; }
/// <summary>
/// 获取或者设置发布者
/// </summary>
public string? Issuer { get; set; }
}
}
(4)、授权服务器运行起来如下:

Microsoft.AspNetCore.Authentication.JwtBearer Microsoft.IdentityModel.Tokens(3)、Program.cs源码如下,红色部分表示健全和授权的重要部分。
1 using Microsoft.AspNetCore.Authentication.JwtBearer;
2 using Microsoft.IdentityModel.Tokens;
3 using PatrickLiu.Net6API.Extensions;
4 using System.Text;
5
6 var builder = WebApplication.CreateBuilder(args);
7
8 builder.Services.AddControllers();
9 builder.Services.AddEndpointsApiExplorer();
10 builder.Services.AddSwaggerGen();
11
12 #region 配置鉴权
13
14 //增加的鉴权逻辑,角色认证、策略认证都是支持的,和Net Core MVC 支持的一样。
15 JWTTokenOption tokenOption = new JWTTokenOption();
16 builder.Configuration.Bind("JWTTokenOption", tokenOption);
17 //builder.Services.Configure<JWTTokenOption>(builder.Configuration.GetSection("JWTTokenOption"));
18 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
19 .AddJwtBearer(option =>
20 {
21 option.TokenValidationParameters = new TokenValidationParameters()
22 {
23 ValidateIssuer = true,//是否验证 Issuer(发行商)
24 ValidateAudience = true,//是否验证 Audience(受众者)
25 ValidateLifetime = true,//是否验证失效时间
26 ValidateIssuerSigningKey = true,//是否验证 Issuer 的签名键
27 ValidAudience=tokenOption.Audience,
28 ValidIssuer=tokenOption.Issuer,// ValidAudience,ValidIssuer这两项的值要和验证中心的只保持一致。
29 IssuerSigningKey=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOption.SecurityKey!))
30 };
31 });
32
33 #endregion
34
35 var app = builder.Build();
36
37 app.UseSwagger();
38 app.UseSwaggerUI();
39
40 app.UseAuthentication();
41 app.UseAuthorization();42
43 app.MapControllers();
44
45 app.Run();
(4)、要实现授权的Controller增加【Authorize】特性,红色部分要注意。using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace PatrickLiu.Net6API.Resouces.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SecondController : ControllerBase
{
/// <summary>
/// 这里使用 JWT 进行授权检查。
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(AuthenticationSchemes =JwtBearerDefaults.AuthenticationScheme)]
public object GetData()
{
return new
{
Id = 1234,
Name = "PatrickLiu"
};
}
}
}
(5)、appsettings.json 配置文件,这里的配置要和【PatrickLiu.Net6API.AuthenticationCenter】项目配置一样,红色部分要注意。{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JWTTokenOption": {
"Audience": "PatrickLiu.com",
"Issuer": "PatrickLiu.com",
"SecurityKey": "12333456677655ffrrffff"
}
}
4、现在是Minimal WebAPI类型项目:
Microsoft.AspNetCore.Authentication.JwtBearer Microsoft.IdentityModel.Tokens(3)、Program.cs 源码如下,红色标注要特别重要。
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using PatrickLiu.Net6API.Extensions;
using PatrickLiu.Net6API.MinimalAPI.Extension;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
#region 1、配置鉴权逻辑
// 堆代码 duidaima.com
//增加的鉴权逻辑,角色认证、策略认证都是支持的,和Net Core MVC 支持的一样。
JWTTokenOption tokenOption = new JWTTokenOption();
builder.Configuration.Bind("JWTTokenOption", tokenOption);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(option =>
{
option.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,//是否验证 Issuer(发行商)
ValidateAudience = true,//是否验证 Audience(受众者)
ValidateLifetime = true,//是否验证失效时间
ValidateIssuerSigningKey = true,//是否验证 Issuer 的签名键
ValidAudience = tokenOption.Audience,
ValidIssuer = tokenOption.Issuer,// ValidAudience,ValidIssuer这两项的值要和验证中心的只保持一致。
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOption.SecurityKey!))
};
});
#endregion
#region 2、配置授权逻辑
//在这里不支持增加授权信息,比如:builder.Services.AddAuthorization(JwtBearerDefaults.AuthenticationScheme);,这样写是不行的, 我们可以扩展实现 IAuthorizeData 来达到同样的目的。
builder.Services.AddAuthorization();
#endregion
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
#region 3、使用鉴权授权中间件
app.UseAuthentication();
app.UseAuthorization();
#endregion
#region 4、实现授权要求
app.MapGet("/User", (int id, string name) =>
{
return "Hello World!";
}).RequireAuthorization(new CustomAuthorizeData()
{
AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme
//可以增加角色授权
//,Roles="",
//可以增加策略授权。
//Policy=""
});
app.MapGet("/Products", (HttpContext context) =>
{
return new
{
Id = 123456,
Name = "IPhone14 Pro Max",
Price = 4839.23,
DateOfProduction = "2023/2/12 23:22"
};
});
#endregion
app.Run();
(4)、扩展 IAuthorizeData 接口实现CustomAuthorizeData,可以实现对MinimalAPI授权。using Microsoft.AspNetCore.Authorization;
namespace PatrickLiu.Net6API.MinimalAPI.Extension
{
public sealed class CustomAuthorizeData : IAuthorizeData
{
public string? Policy { get; set; }
public string? Roles { get; set; }
public string? AuthenticationSchemes { get; set; }
}
}
(5)、appsettings.json 配置文件源码如下,红色部分是重要代码。{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JWTTokenOption": {
"Audience": "PatrickLiu.com",
"Issuer": "PatrickLiu.com",
"SecurityKey": "12333456677655ffrrffff"
}
}
三、结束语