This commit is contained in:
2026-10-05 22:30:29 +03:30
parent ac0ebe601e
commit e379faaa07
6 changed files with 214 additions and 48 deletions
+4
View File
@@ -1,3 +1,7 @@
using System;
using System.Text;
using System.Security.Cryptography;
namespace xIds.Helpers namespace xIds.Helpers
{ {
/// <summary> /// <summary>
+2 -2
View File
@@ -180,7 +180,7 @@ namespace xIds.Interfaces
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<XApiKeyDto> AddApiKeyAsync( Task<XApiKeyDto> AddApiKeyAsync(
XApiKey item, XApiKeyDto item,
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
); );
@@ -537,7 +537,7 @@ namespace xIds.Interfaces
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<XApiKeyDto>> GetApplicationApiKeys( Task<IEnumerable<XApiKeyDto>> GetApplicationApiKeys(
Guid applicationId, int applicationId,
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
); );
@@ -30,7 +30,7 @@ namespace xIds.Providers
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task<XApiKeyDto> AddApiKeyAsync( public async Task<XApiKeyDto> AddApiKeyAsync(
XApiKey item, XApiKeyDto item,
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
@@ -86,12 +86,6 @@ namespace xIds.Providers
// //
var entity = item.MapConvert<XApiKey, XApiKeyDto>(); var entity = item.MapConvert<XApiKey, XApiKeyDto>();
if (entity.Id.IsValidIntId())
{
entity.Id = -1;
}
//
var entry = await dbContext.ApiKeys.AddAsync( var entry = await dbContext.ApiKeys.AddAsync(
entity: entity, entity: entity,
cancellationToken: cancellationToken cancellationToken: cancellationToken
@@ -175,19 +169,8 @@ namespace xIds.Providers
// Update Data on Exists Entity ... // Update Data on Exists Entity ...
exists = exists.UpdateData( exists = exists.UpdateData(
updateWith: item, updateWith: item,
propertyWhiteList: [ propertyWhiteList: [],
nameof(XApiKey.KeyHash), propertyBlackList: []
nameof(XApiKey.KeyPrefix),
nameof(XApiKey.ExpiresAt),
nameof(XApiKey.CreatedOn),
nameof(XApiKey.RevokedAt),
nameof(XApiKey.RevokedBy),
nameof(XApiKey.LastUsedAt),
nameof(XApiKey.AllowedIPs),
nameof(XApiKey.ApplicationId),
nameof(XApiKey.AllowedScopes),
nameof(XApiKey.RateLimitPerMinute),
]
); );
// //
@@ -121,13 +121,8 @@ namespace xIds.Providers
// Update Data on Exists Entity ... // Update Data on Exists Entity ...
exists = exists.UpdateData( exists = exists.UpdateData(
updateWith: item, updateWith: item,
propertyWhiteList: [ propertyWhiteList: [],
nameof(XApiKeyUsage.ApiKeyId), propertyBlackList: [
nameof(XApiKeyUsage.Endpoint),
nameof(XApiKeyUsage.ClientIP),
nameof(XApiKeyUsage.HttpMethod),
nameof(XApiKeyUsage.StatusCode),
nameof(XApiKeyUsage.RequestedOn),
nameof(XApiKeyUsage.ResponseTimeMs), nameof(XApiKeyUsage.ResponseTimeMs),
] ]
); );
@@ -129,18 +129,16 @@ namespace xIds.Providers
XException.NotAllowed.Throw(); XException.NotAllowed.Throw();
} }
//
item.UpdatedAt = DateTime.UtcNow;
// //
// Update Data on Exists Entity ... // Update Data on Exists Entity ...
exists = exists.UpdateData( exists = exists.UpdateData(
updateWith: item, updateWith: item,
propertyWhiteList: [ propertyWhiteList: [],
nameof(XApplication.Name), propertyBlackList: [
nameof(XApplication.Type), nameof(XApplication.ApiKeys),
nameof(XApplication.OwnerId),
nameof(XApplication.IsActive),
nameof(XApplication.CreatedOn),
nameof(XApplication.UpdatedAt),
nameof(XApplication.Description),
] ]
); );
@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using xIds.Helpers;
using System.Threading; using System.Threading;
using xCommons.Extensions; using xCommons.Extensions;
using xIdentityModels.Dtos; using xIdentityModels.Dtos;
@@ -7,6 +8,7 @@ using xExceptions.Constants;
using System.Threading.Tasks; using System.Threading.Tasks;
using xIdentityModels.Models; using xIdentityModels.Models;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Cryptography;
namespace xIds.Providers namespace xIds.Providers
{ {
@@ -80,15 +82,43 @@ namespace xIds.Providers
{ {
expiration = TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes); expiration = TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes);
} }
//
var
// //
var item = new XApiKeyDto // Generate New Key ...
(string plainKey, string keyHash, string prefix) = XApiKeyHelper.Generate();
var expireAt = DateTime.UtcNow.Add(expiration.Value);
//
var _allowedScopes = scopes.ToJSON();
var _allowedIPs = allowedIPs.ToListString();
//
// Instance Dto Item ...
var result = new XApiKeyDto
{ {
RevokedAt = null,
} KeyHash = keyHash,
LastUsedAt = null,
KeyPrefix = prefix,
ExpiresAt = expireAt,
RevokedBy = string.Empty,
AllowedIPs = _allowedIPs,
CreatedOn = DateTime.UtcNow,
ApplicationId = applicationId,
AllowedScopes = _allowedScopes,
RateLimitPerMinute = rateLimit.Value
};
//
// Add Item to Database ...
result = await AddApiKeyAsync(
item: item,
userInfo: userInfo,
cancellationToken: cancellationToken
);
//
return result;
} }
/// <summary> /// <summary>
@@ -103,7 +133,65 @@ namespace xIds.Providers
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
{ } {
//
// Validate ...
if (
apiKeyId.IsDefaultGuid() ||
userInfo.IsNullOrDefault())
{
XException.InvalidArgs.Throw();
}
//
// Retrieve ApiKey ...
var item = await GetApiKeyAsync(
id: apiKeyId,
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (item.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
// Permission Checking ...
var application = await GetApplicationAsync(
userInfo: userInfo,
includeBuilder: null,
id: item.ApplicationId,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (application.IsNullOrDefault())
{
XException.NotFound.Throw();
}
if (!IsOwned(application, userInfo))
{
XException.NotAllowed.Throw();
}
//
// Update Revoke Info ...
item.RevokedAt = DateTime.UtcNow;
item.RevokedBy = userInfo.UserId;
//
item = await UpdateApiKeyAsync(
id: item.Id,
item: item,
userInfo: userInfo,
cancellationToken: cancellationToken
);
//
var result = !item.IsNullOrDefault();
return result;
}
/// <summary> /// <summary>
/// Renew Specified Api Key ... /// Renew Specified Api Key ...
@@ -119,7 +207,61 @@ namespace xIds.Providers
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
{ } {
//
// Validate ...
if (
apiKeyId.IsDefaultGuid() ||
userInfo.IsNullOrDefault()
)
{
XException.InvalidArgs.Throw();
}
//
// Retrieve Item ...
var result = await GetApiKeyAsync(
id: apiKeyId,
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (result.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
// Expired Date ...
DateTime? expiredDate = null;
if (!newExpiration.HasValue)
{
//
newExpiration = TimeSpan
.FromMinutes(apiKeyConfiguration.DefaultExpirationMinutes);
expiredDate = DateTime.UtcNow.Add(newExpiration.Value);
}
if (!expiredDate.HasValue)
{
XException.InvalidArgs.Throw();
}
//
// Update Item ...
result.ExpiresAt = expiredDate.Value;
//
result = await UpdateApiKeyAsync(
item: result,
id: result.Id,
userInfo: userInfo,
cancellationToken: cancellationToken
);
//
return result;
}
/// <summary> /// <summary>
/// Retrieve All Api Keys for Specified Application ... /// Retrieve All Api Keys for Specified Application ...
@@ -129,11 +271,52 @@ namespace xIds.Providers
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<XApiKeyDto>> GetApplicationApiKeys( public async Task<IEnumerable<XApiKeyDto>> GetApplicationApiKeys(
Guid applicationId, int applicationId,
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
{ } {
//
// Validate ...
if (
userInfo.IsNullOrDefault() ||
!applicationId.IsValidIntId()
)
{
XException.InvalidArgs.Throw();
}
//
// Permission Checking ...
var application = await GetApplicationAsync(
userInfo: userInfo,
includeBuilder: null,
id: applicationId,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (application.IsNullOrDefault())
{
XException.NotFound.Throw();
}
if (!IsOwned(application, userInfo))
{
XException.NotAllowed.Throw();
}
//
var result = await FindManyApiKeyAsync(
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken,
orderBuilder: x => x.OrderBy(y => y.Id),
predicate: x => x.ApplicationId == applicationId
);
//
return result;
}
/// <summary> /// <summary>
/// Validate Specified Api Key in based on ClientIP ... /// Validate Specified Api Key in based on ClientIP ...
@@ -149,7 +332,10 @@ namespace xIds.Providers
XUserClaimsInfoDto userInfo = null, XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default CancellationToken cancellationToken = default
) )
{ } {
//
}
#endregion #endregion
} }
} }