323 lines
9.5 KiB
C#
323 lines
9.5 KiB
C#
using System;
|
|
using System.Linq;
|
|
using xModels.Dtos;
|
|
using xIds.DbContext;
|
|
using xIds.Interfaces;
|
|
using xCommons.Extensions;
|
|
using xIds.Configurations;
|
|
using xIdentityModels.Dtos;
|
|
using xExceptions.Constants;
|
|
using System.Threading.Tasks;
|
|
using xIdentityModels.Models;
|
|
using System.Linq.Expressions;
|
|
using IdentityServer4.Extensions;
|
|
using xIdentityModels.Extensions;
|
|
using Microsoft.EntityFrameworkCore.Query;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
|
|
namespace xIds.Providers
|
|
{
|
|
/// <summary>
|
|
/// a Service For Manage Security Applications and also Api Key(s) ...
|
|
/// </summary>
|
|
public partial class XApplicationProvider : IXApplicationProvider
|
|
{
|
|
private readonly IMemoryCache cache;
|
|
private readonly string permittedRole;
|
|
private readonly XIdentityDbContext dbContext;
|
|
private readonly IXIdentityManager identityManager;
|
|
private readonly XDataServiceConfiguration configuration;
|
|
private readonly XApiKeyConfiguration apiKeyConfiguration;
|
|
|
|
public XApplicationProvider(
|
|
IMemoryCache cache,
|
|
XIdentityDbContext dbContext,
|
|
IXIdentityManager identityManager,
|
|
XDataServiceConfiguration configuration,
|
|
XApiKeyConfiguration apiKeyConfiguration,
|
|
string permittedRole = "admin"
|
|
)
|
|
{
|
|
//
|
|
this.cache = cache;
|
|
this.dbContext = dbContext;
|
|
this.permittedRole = permittedRole;
|
|
this.configuration = configuration;
|
|
this.identityManager = identityManager;
|
|
this.apiKeyConfiguration = apiKeyConfiguration;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve Owner ...
|
|
/// </summary>
|
|
/// <param name="ownerId"></param>
|
|
/// <returns></returns>
|
|
public async Task<XPersonDto> GetOwner(string ownerId)
|
|
{
|
|
//
|
|
if (ownerId.IsNullOrEmpty())
|
|
{
|
|
XException.InvalidArgs.Throw();
|
|
}
|
|
|
|
//
|
|
var user = await identityManager.GetUserAsync(ownerId);
|
|
XPersonDto result = user.ToXPerson();
|
|
if (result.IsNullOrDefault())
|
|
{
|
|
XException.NotFound.Throw();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check Specifed User Info is Owned for Action or not ...
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="userInfo"></param>
|
|
/// <returns></returns>
|
|
public bool IsOwned(
|
|
XApplication source,
|
|
XUserClaimsInfoDto userInfo = null
|
|
)
|
|
{
|
|
//
|
|
var result =
|
|
!source.IsNullOrDefault() &&
|
|
!userInfo.IsNullOrDefault() &&
|
|
(userInfo.UserId == source.OwnerId ||
|
|
userInfo.Roles
|
|
.Any(r =>
|
|
r.ToNormalString() == permittedRole.ToNormalString()));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check Specifed User Info is Owned for Action or not ...
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="userInfo"></param>
|
|
/// <returns></returns>
|
|
public bool IsOwned(
|
|
XApplicationDto source,
|
|
XUserClaimsInfoDto userInfo = null
|
|
)
|
|
{
|
|
//
|
|
var result =
|
|
!source.IsNullOrDefault() &&
|
|
!userInfo.IsNullOrDefault() &&
|
|
(userInfo.UserId == source.OwnerId ||
|
|
userInfo.Roles
|
|
.Any(r =>
|
|
r.ToNormalString() == permittedRole.ToNormalString()));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Normalize an XQuery based on Data Service Configurations ...
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="configuration"></param>
|
|
/// <returns></returns>
|
|
public XQuery NormalizeQuery(
|
|
XQuery source,
|
|
XDataServiceConfiguration configuration //
|
|
)
|
|
{
|
|
//
|
|
if (source.IsNull())
|
|
{
|
|
source = new XQuery();
|
|
}
|
|
|
|
//
|
|
// Page Size Normalization ...
|
|
if (source.PageSize < configuration.PagingConfiguration.MinAvailablePageSize)
|
|
{
|
|
source.PageSize = configuration.PagingConfiguration.MinAvailablePageSize;
|
|
}
|
|
if (source.PageSize > configuration.PagingConfiguration.MaxAvailablePageSize)
|
|
{
|
|
source.PageSize = configuration.PagingConfiguration.MaxAvailablePageSize;
|
|
}
|
|
|
|
//
|
|
return source;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepare a Queryable of Items ...
|
|
/// </summary>
|
|
/// <param name="predicate"></param>
|
|
/// <param name="orderBuilder"></param>
|
|
/// <param name="includeBuilder"></param>
|
|
/// <returns></returns>
|
|
public IQueryable<XApplication> GetApplicationsQeryable(
|
|
Expression<Func<XApplication, bool>> predicate = null,
|
|
Func<IQueryable<XApplication>, IOrderedQueryable<XApplication>> orderBuilder = null,
|
|
Func<IQueryable<XApplication>, IIncludableQueryable<XApplication, object>> includeBuilder = null
|
|
)
|
|
{
|
|
//
|
|
// Global Result ...
|
|
var result = dbContext.Applications.AsQueryable();
|
|
|
|
//
|
|
// Handle Filtering ...
|
|
if (!predicate.IsNull())
|
|
{
|
|
result = result.Where(predicate);
|
|
}
|
|
|
|
//
|
|
// Handle Including ...
|
|
if (!includeBuilder.IsNull())
|
|
{
|
|
result = includeBuilder(result);
|
|
}
|
|
|
|
//
|
|
// Handle Ordering ...
|
|
if (!orderBuilder.IsNull())
|
|
{
|
|
result = orderBuilder(result);
|
|
}
|
|
|
|
//
|
|
// Return result ...
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepare a Queryable of Items ...
|
|
/// </summary>
|
|
/// <param name="predicate"></param>
|
|
/// <param name="orderBuilder"></param>
|
|
/// <param name="includeBuilder"></param>
|
|
/// <returns></returns>
|
|
public IQueryable<XApiKey> GetApiKeysQeryable(
|
|
Expression<Func<XApiKey, bool>> predicate = null,
|
|
Func<IQueryable<XApiKey>, IOrderedQueryable<XApiKey>> orderBuilder = null,
|
|
Func<IQueryable<XApiKey>, IIncludableQueryable<XApiKey, object>> includeBuilder = null
|
|
)
|
|
{
|
|
//
|
|
// Global Result ...
|
|
var result = dbContext.ApiKeys.AsQueryable();
|
|
|
|
//
|
|
// Handle Filtering ...
|
|
if (!predicate.IsNull())
|
|
{
|
|
result = result.Where(predicate);
|
|
}
|
|
|
|
//
|
|
// Handle Including ...
|
|
if (!includeBuilder.IsNull())
|
|
{
|
|
result = includeBuilder(result);
|
|
}
|
|
|
|
//
|
|
// Handle Ordering ...
|
|
if (!orderBuilder.IsNull())
|
|
{
|
|
result = orderBuilder(result);
|
|
}
|
|
|
|
//
|
|
// Return result ...
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepare a Queryable of Items ...
|
|
/// </summary>
|
|
/// <param name="predicate"></param>
|
|
/// <param name="orderBuilder"></param>
|
|
/// <param name="includeBuilder"></param>
|
|
/// <returns></returns>
|
|
public IQueryable<XApiKeyUsage> GetApiKeyUsagesQeryable(
|
|
Expression<Func<XApiKeyUsage, bool>> predicate = null,
|
|
Func<IQueryable<XApiKeyUsage>, IOrderedQueryable<XApiKeyUsage>> orderBuilder = null,
|
|
Func<IQueryable<XApiKeyUsage>, IIncludableQueryable<XApiKeyUsage, object>> includeBuilder = null
|
|
)
|
|
{
|
|
//
|
|
// Global Result ...
|
|
var result = dbContext.ApiKeyUsages.AsQueryable();
|
|
|
|
//
|
|
// Handle Filtering ...
|
|
if (!predicate.IsNull())
|
|
{
|
|
result = result.Where(predicate);
|
|
}
|
|
|
|
//
|
|
// Handle Including ...
|
|
if (!includeBuilder.IsNull())
|
|
{
|
|
result = includeBuilder(result);
|
|
}
|
|
|
|
//
|
|
// Handle Ordering ...
|
|
if (!orderBuilder.IsNull())
|
|
{
|
|
result = orderBuilder(result);
|
|
}
|
|
|
|
//
|
|
// Return result ...
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle Rate Limit Checking ...
|
|
/// </summary>
|
|
/// <param name="apiKeyId"></param>
|
|
/// <param name="limitPerMinute"></param>
|
|
/// <returns></returns>
|
|
private bool CheckRateLimit(
|
|
Guid apiKeyId,
|
|
int limitPerMinute
|
|
)
|
|
{
|
|
//
|
|
var cacheKey = $"ratelimit:{apiKeyId}";
|
|
var currentCount = cache.GetOrCreate(
|
|
cacheKey,
|
|
entry =>
|
|
{
|
|
//
|
|
entry.SlidingExpiration = TimeSpan.FromMinutes(1);
|
|
return 0;
|
|
}
|
|
);
|
|
|
|
//
|
|
if (currentCount >= limitPerMinute) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
cache.Set(
|
|
cacheKey,
|
|
currentCount + 1,
|
|
TimeSpan.FromMinutes(1)
|
|
);
|
|
|
|
//
|
|
return true;
|
|
}
|
|
}
|
|
} |