我有一个 API 设置,允许下订单、查找产品信息、报告等。每个 API 密钥都有特定的权限,可以访问或不能访问哪些控制器/方法,以及应该省略的字段。不幸的是,现在我在字典类中进行了硬编码,并且想从数据库中提取这些权限。
问题是我不想在每次调用方法时都调用数据库来查找权限以避免性能下降。有没有办法在发生更改时随时发布这些设置/权限(使用管理页面)并让 API 在某种字典中“记住”它们在内存中?此外,在重新启动 API 时,我猜这些已被清除,因此我需要一种方法来在 API 初始化时提取此信息。不确定设计这个的最佳方法是什么,任何建议都有帮助谢谢。
编辑:我避免使用角色,因为我有数百个 API 密钥,每个密钥都有不同的设置/权限,我猜每个都需要一个特定的角色。
你不能只使用基于标准角色的授权吗?
这是我在设置时遵循的内容https://weblog.west-wind.com/posts/2021/Mar/09/Role-based-JWT-Tokens-in-ASPNET-Core
[Authorize(Roles = "admin")]
[HttpPost]
public async Task<IActionResult> Post(RoomDelegate roomDelegate) =>
HandleResult(await Mediator.Send(new Post.Command { RoomDelegate = roomDelegate }));
将您的角色存储在代币声明中。
public class TokenService
{
private readonly IConfiguration _config;
private readonly UserManager<AppUser> _userManager;
public TokenService(IConfiguration config, UserManager<AppUser> userManager)
{
_config = config;
_userManager = userManager;
}
public IConfiguration Config { get; }
public async Task<string> CreateToken(AppUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName ),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Email, user.Email),
};
var roles = await _userManager.GetRolesAsync(user);
foreach (var role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["TokenKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
var tokenDescription = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddMinutes(10),
SigningCredentials = creds
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescription);
return tokenHandler.WriteToken(token);
}
public RefreshToken GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return new RefreshToken { Token = Convert.ToBase64String(randomNumber) };
}
}
然后您可以使用自定义属性来强制执行需要有效 API 密钥的授权策略,例如
public class ApiKeyAuthorizeAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
//assuming the API keys and all other info required for validation are passed in via a request header
var requestHeaders = context.HttpContext.Request.Headers;
//some service containg methods to validate requests using the API keys stored within a dictionary
var apiKeyValidationService = context.HttpContext.RequestServices.GetService<IApiKeyValidationService>();
var result = apiKeyValidationService.IsRequestAuthorized(requestHeaders);
if (!result.IsAuthorised)
{
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
var logger = context.HttpContext.RequestServices.GetService<ILogger<ApiKeyAuthorizeAttribute>>();
logger.LogWarning(result.FailureMessage);
}
}
}
然后,您可以使用自定义属性装饰任何要强制执行授权的方法。
[HttpPost]
[ApiKeyAuthorize]
public async Task<IActionResult> ApiMethod(Data data)
{
//Do something
}