118 lines
4.3 KiB
C#
118 lines
4.3 KiB
C#
using KTUSAPS.Data;
|
|
using KTUSAPS.Data.Model;
|
|
using KTUSAPS.Extensions;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace KTUSAPS.Auth
|
|
{
|
|
public class SaPsAuthorizationHandler : IAuthorizationHandler
|
|
{
|
|
private readonly IServiceProvider serviceProvider;
|
|
public SaPsAuthorizationHandler(IServiceProvider serviceProvider)
|
|
{
|
|
this.serviceProvider = serviceProvider;
|
|
}
|
|
|
|
public async Task HandleAsync(AuthorizationHandlerContext context)
|
|
{
|
|
var cache = new AuthProcessingCache(context.User, serviceProvider);
|
|
foreach (var requirement in context.Requirements)
|
|
{
|
|
if (requirement is AdminRequirement adminRequirement)
|
|
await HandleRequirementAsync(context, adminRequirement, cache);
|
|
if (requirement is MyIssueRequirement myIssueRequirement)
|
|
await HandleRequirementAsync(context, myIssueRequirement, cache);
|
|
}
|
|
}
|
|
|
|
private async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyIssueRequirement myIssueRequirement, AuthProcessingCache cache)
|
|
{
|
|
if(context.Resource is not Issue issue)
|
|
throw new Exception($"'{nameof(MyIssueRequirement)}' must be issued with resource of type '{nameof(Issue)}'");
|
|
|
|
if(issue.UserID == context.User.GetUserId())
|
|
{
|
|
context.Succeed(myIssueRequirement);
|
|
return;
|
|
}
|
|
|
|
if(await cache.DetermineIsAdminAsync())
|
|
{
|
|
context.Succeed(myIssueRequirement);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private async Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminRequirement adminRequirement, AuthProcessingCache cache)
|
|
{
|
|
if(await cache.DetermineIsAdminAsync())
|
|
{
|
|
context.Succeed(adminRequirement);
|
|
return;
|
|
}
|
|
context.Fail();
|
|
}
|
|
|
|
|
|
private class AuthProcessingCache
|
|
{
|
|
private readonly ClaimsPrincipal _user;
|
|
private readonly IServiceProvider _serviceProvider;
|
|
|
|
private bool? isAdmin;
|
|
public bool IsAdmin => determineIsAdminCached();
|
|
|
|
public AuthProcessingCache(ClaimsPrincipal user, IServiceProvider serviceProvider) {
|
|
_user = user;
|
|
_serviceProvider = serviceProvider;
|
|
}
|
|
|
|
private bool determineIsAdminCached()
|
|
{
|
|
if (isAdmin == null)
|
|
isAdmin = determineIsAdmin();
|
|
return isAdmin.Value;
|
|
}
|
|
|
|
private bool determineIsAdmin()
|
|
{
|
|
var objectId = _user.GetObjectId();
|
|
if (objectId == default)
|
|
return false;
|
|
using var scope = _serviceProvider.CreateScope();
|
|
var dataContext = scope.ServiceProvider.GetRequiredService<SAPSDataContext>();
|
|
var admin = dataContext.Admins.Where(a => a.UserId == objectId).FirstOrDefault();
|
|
if (admin != default)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
private async ValueTask<bool> determineIsAdminAsync()
|
|
{
|
|
var idclaim = _user.Claims.Where(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").FirstOrDefault();
|
|
if (idclaim == default)
|
|
return false;
|
|
using var scope = _serviceProvider.CreateScope();
|
|
var dataContext = scope.ServiceProvider.GetRequiredService<SAPSDataContext>();
|
|
var admin = await dataContext.Admins.Where(a => a.UserId == idclaim.Value).FirstOrDefaultAsync();
|
|
if (admin != default)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public async ValueTask<bool> DetermineIsAdminAsync()
|
|
{
|
|
if (isAdmin == null)
|
|
isAdmin = await determineIsAdminAsync();
|
|
return isAdmin.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|