Compare commits
No commits in common. "b20dad720849ae9cdd2d2c4997469fb09de6a1ab" and "cc91622bde615daab8a1b7511c477528f8374f53" have entirely different histories.
b20dad7208
...
cc91622bde
|
|
@ -1,50 +0,0 @@
|
||||||
using System.Security.Claims;
|
|
||||||
using AspNetCore.Authentication.ApiKey;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace NejCommon.Authorization;
|
|
||||||
|
|
||||||
public partial class PermissionHandler : AuthorizationHandler<PermissionRequirement>
|
|
||||||
{
|
|
||||||
protected override async Task HandleRequirementAsync(
|
|
||||||
AuthorizationHandlerContext context,
|
|
||||||
PermissionRequirement requirement)
|
|
||||||
{
|
|
||||||
if (context.Resource is not HttpContext http)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var companyId = http.GetRouteValue("companyId")?.ToString();
|
|
||||||
if (companyId == null)
|
|
||||||
{
|
|
||||||
context.Succeed(requirement);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var authType = context.User.Identity?.AuthenticationType;
|
|
||||||
if (authType == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool allowed;
|
|
||||||
|
|
||||||
if (authType == ApiKeyDefaults.AuthenticationScheme)
|
|
||||||
{
|
|
||||||
var id = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
||||||
if (id == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
allowed = await CheckApiKeyPermission(id, companyId, requirement.Permission);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var sub = context.User.FindFirst("sub")?.Value;
|
|
||||||
if (sub == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
allowed = await CheckUserPermission(sub, companyId, requirement.Permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowed)
|
|
||||||
context.Succeed(requirement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
namespace NejCommon.Authorization;
|
|
||||||
|
|
||||||
public class PermissionRequirement : IAuthorizationRequirement
|
|
||||||
{
|
|
||||||
public string? Permission { get; }
|
|
||||||
|
|
||||||
public PermissionRequirement(string? permission)
|
|
||||||
{
|
|
||||||
Permission = permission;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using AspNetCore.Authentication.ApiKey;
|
|
||||||
using AutoMapPropertyHelper;
|
|
||||||
using NejCommon.Models;
|
|
||||||
|
|
||||||
namespace NejCommon.Models;
|
|
||||||
|
|
||||||
public partial class ApiKey : IApiKey
|
|
||||||
{
|
|
||||||
[AutoMapProperty("Response")]
|
|
||||||
public string Id { get; set; } = NanoidDotNet.Nanoid.Generate(size: 64);
|
|
||||||
[AutoMapProperty("Request")]
|
|
||||||
public string Name { get; set; } = null!;
|
|
||||||
public byte[] LookupHash { get; set; } = null!;
|
|
||||||
public string KeyHash { get; set; } = null!;
|
|
||||||
|
|
||||||
[AutoMapProperty("Response")]
|
|
||||||
public bool Revoked { get; set; }
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
public string key = "";
|
|
||||||
[NotMapped]
|
|
||||||
[AutoMapProperty("CreateResponse")]
|
|
||||||
public string Key
|
|
||||||
{
|
|
||||||
get => key;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
key = value;
|
|
||||||
LookupHash = ComputeLookupHash(value);
|
|
||||||
KeyHash = ComputeStrongHash(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[NotMapped]
|
|
||||||
public string OwnerName => Id;
|
|
||||||
[NotMapped]
|
|
||||||
public IReadOnlyCollection<Claim> Claims => [
|
|
||||||
new Claim(ClaimTypes.NameIdentifier, Id),
|
|
||||||
new Claim(ClaimTypes.Name, Name)
|
|
||||||
];
|
|
||||||
|
|
||||||
public static byte[] ComputeLookupHash(string key)
|
|
||||||
{
|
|
||||||
using var sha256 = SHA256.Create();
|
|
||||||
return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
|
|
||||||
}
|
|
||||||
public static string ComputeStrongHash(string key)
|
|
||||||
{
|
|
||||||
return BCrypt.Net.BCrypt.EnhancedHashPassword(key);
|
|
||||||
}
|
|
||||||
public bool VerifyStrongHash(string key){
|
|
||||||
return BCrypt.Net.BCrypt.EnhancedVerify(key, KeyHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class ApiKeyResponse : ApiKeyRequest {}
|
|
||||||
public partial class ApiKeyCreateResponse : ApiKeyResponse {}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
using AspNetCore.Authentication.ApiKey;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using NanoidDotNet;
|
|
||||||
using NejCommon.Models;
|
|
||||||
|
|
||||||
namespace NejCommon.Services;
|
|
||||||
|
|
||||||
public partial class ApiKeyProvider : IApiKeyProvider, IScopedService
|
|
||||||
{
|
|
||||||
private readonly ILogger<ApiKeyProvider> _logger;
|
|
||||||
|
|
||||||
public async Task<IApiKey> ProvideAsync(string key)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var lookup = ApiKey.ComputeLookupHash(key);
|
|
||||||
|
|
||||||
var apiKey = await GetApiKeySet().FirstOrDefaultAsync(x => x.LookupHash.SequenceEqual(lookup));
|
|
||||||
if (apiKey == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!apiKey.VerifyStrongHash(key))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
apiKey.Key = key;
|
|
||||||
|
|
||||||
// write your validation implementation here and return an instance of a valid ApiKey or retun null for an invalid key.
|
|
||||||
// return await _apiKeyRepository.GetApiKeyAsync(key);
|
|
||||||
return apiKey;
|
|
||||||
}
|
|
||||||
catch (System.Exception exception)
|
|
||||||
{
|
|
||||||
_logger.LogError(exception, exception.Message);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateKey() => "nej-" + Nanoid.Generate(size: 256);
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user