Permissions and authorizations at the user role level have been added to the application.
parent
8e54fdc184
commit
cb6fa0507a
|
@ -11,7 +11,7 @@
|
||||||
<NBBPackageVersion>6.0.30</NBBPackageVersion>
|
<NBBPackageVersion>6.0.30</NBBPackageVersion>
|
||||||
<EntityFrameworkCorePackageVersion>6.0.1</EntityFrameworkCorePackageVersion>
|
<EntityFrameworkCorePackageVersion>6.0.1</EntityFrameworkCorePackageVersion>
|
||||||
<NetmashExtensionsSwaggerPackageVersion>1.0.7</NetmashExtensionsSwaggerPackageVersion>
|
<NetmashExtensionsSwaggerPackageVersion>1.0.7</NetmashExtensionsSwaggerPackageVersion>
|
||||||
<NetmashTuitioAuthenticationPackageVersion>2.2.0</NetmashTuitioAuthenticationPackageVersion>
|
<NetmashTuitioAuthenticationPackageVersion>2.2.1</NetmashTuitioAuthenticationPackageVersion>
|
||||||
<NetmashDatabaseMigrationPackageVersion>1.2.0</NetmashDatabaseMigrationPackageVersion>
|
<NetmashDatabaseMigrationPackageVersion>1.2.0</NetmashDatabaseMigrationPackageVersion>
|
||||||
<CorreoPublishedLanguage>1.0.1</CorreoPublishedLanguage>
|
<CorreoPublishedLanguage>1.0.1</CorreoPublishedLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
|
||||||
|
<PackageReference Include="Netmash.Security.Authentication.Tuitio" Version="$(NetmashTuitioAuthenticationPackageVersion)" />
|
||||||
<PackageReference Include="NBB.Messaging.Abstractions" Version="$(NBBPackageVersion)" />
|
<PackageReference Include="NBB.Messaging.Abstractions" Version="$(NBBPackageVersion)" />
|
||||||
<PackageReference Include="NetworkResurrector.Agent.Wrapper" Version="1.1.0" />
|
<PackageReference Include="NetworkResurrector.Agent.Wrapper" Version="1.1.0" />
|
||||||
<PackageReference Include="NetworkResurrector.Server.Wrapper" Version="1.1.1" />
|
<PackageReference Include="NetworkResurrector.Server.Wrapper" Version="1.1.1" />
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
using MediatR;
|
||||||
|
using Netmash.Security.Authentication.Tuitio.Abstractions;
|
||||||
|
using NetworkResurrector.Api.Domain.Repositories;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NetworkResurrector.Api.Application.Queries
|
||||||
|
{
|
||||||
|
public class GetUserPermissions
|
||||||
|
{
|
||||||
|
public class Query : IRequest<Model> { }
|
||||||
|
|
||||||
|
public class Model
|
||||||
|
{
|
||||||
|
public IEnumerable<string> Permissions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueryHandler : IRequestHandler<Query, Model>
|
||||||
|
{
|
||||||
|
private readonly IUserContextAccessor _userContext;
|
||||||
|
private readonly ISecurityRepository _securityRepository;
|
||||||
|
|
||||||
|
public QueryHandler(IUserContextAccessor userContext, ISecurityRepository securityRepository)
|
||||||
|
{
|
||||||
|
_userContext=userContext;
|
||||||
|
_securityRepository=securityRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Model> Handle(Query request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var roles = _userContext.UserRoles.Select(r => r.id);
|
||||||
|
var permissions = await _securityRepository.GetUserPermissionCodes(roles);
|
||||||
|
return new Model()
|
||||||
|
{
|
||||||
|
Permissions = permissions
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using NetworkResurrector.Api.Domain.Data.EntityTypeConfiguration;
|
||||||
using NetworkResurrector.Api.Domain.Data.EntityTypeConfiguration.Power;
|
using NetworkResurrector.Api.Domain.Data.EntityTypeConfiguration.Power;
|
||||||
using NetworkResurrector.Api.Domain.Data.EntityTypeConfiguration.Security;
|
using NetworkResurrector.Api.Domain.Data.EntityTypeConfiguration.Security;
|
||||||
using NetworkResurrector.Api.Domain.Entities;
|
using NetworkResurrector.Api.Domain.Entities;
|
||||||
|
using NetworkResurrector.Api.Domain.Entities.Security;
|
||||||
|
|
||||||
namespace NetworkResurrector.Api.Domain.Data.DbContexts
|
namespace NetworkResurrector.Api.Domain.Data.DbContexts
|
||||||
{
|
{
|
||||||
|
@ -10,6 +11,8 @@ namespace NetworkResurrector.Api.Domain.Data.DbContexts
|
||||||
{
|
{
|
||||||
public DbSet<Machine> Machines { get; set; }
|
public DbSet<Machine> Machines { get; set; }
|
||||||
public DbSet<Entities.Power.PowerActionConfiguration> PowerActionConfigurations { get; set; }
|
public DbSet<Entities.Power.PowerActionConfiguration> PowerActionConfigurations { get; set; }
|
||||||
|
public DbSet<UserRoleAuthorization> UserRoleAuthorizations { get; set; }
|
||||||
|
public DbSet<PermissionHierarchy> PermissionHierarchies { get; set; }
|
||||||
|
|
||||||
public NetworkDbContext(DbContextOptions<NetworkDbContext> options)
|
public NetworkDbContext(DbContextOptions<NetworkDbContext> options)
|
||||||
: base(options)
|
: base(options)
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace NetworkResurrector.Api.Domain.Data
|
||||||
public static void AddDataAccess(this IServiceCollection services)
|
public static void AddDataAccess(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddScoped<INetworkRepository, NetworkRepository>();
|
services.AddScoped<INetworkRepository, NetworkRepository>();
|
||||||
|
services.AddScoped<ISecurityRepository, SecurityRepository>();
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddDbContextPool<NetworkDbContext>(
|
.AddDbContextPool<NetworkDbContext>(
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NetworkResurrector.Api.Domain.Data.DbContexts;
|
||||||
|
using NetworkResurrector.Api.Domain.Entities.Security;
|
||||||
|
using NetworkResurrector.Api.Domain.Repositories;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NetworkResurrector.Api.Domain.Data.Repositories
|
||||||
|
{
|
||||||
|
public class SecurityRepository : ISecurityRepository
|
||||||
|
{
|
||||||
|
private readonly NetworkDbContext _dbContext;
|
||||||
|
|
||||||
|
public SecurityRepository(NetworkDbContext dbContext)
|
||||||
|
{
|
||||||
|
_dbContext=dbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task BuildChildrenHierarchy(Permission permission)
|
||||||
|
{
|
||||||
|
var children = await _dbContext.PermissionHierarchies
|
||||||
|
.Include(z => z.Child)
|
||||||
|
.Where(z => z.ParentPermissionId == permission.PermissionId)
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToArrayAsync();
|
||||||
|
|
||||||
|
if (children == null || !children.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
permission.Children = children;
|
||||||
|
|
||||||
|
foreach (var element in permission.Children)
|
||||||
|
{
|
||||||
|
await BuildChildrenHierarchy(element.Child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetPermissionCodes(IEnumerable<Permission> permissions)
|
||||||
|
{
|
||||||
|
var result = new List<string>();
|
||||||
|
foreach (var permission in permissions)
|
||||||
|
{
|
||||||
|
result.Add(permission.PermissionCode);
|
||||||
|
if (permission.Children != null && permission.Children.Count > 0)
|
||||||
|
{
|
||||||
|
var children = permission.Children.Select(ch => ch.Child);
|
||||||
|
var childrenCodes = GetPermissionCodes(children);
|
||||||
|
result.AddRange(childrenCodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.Distinct();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<Permission>> GetUserPermissions(IEnumerable<int> roles)
|
||||||
|
{
|
||||||
|
var authorizations = await _dbContext.UserRoleAuthorizations
|
||||||
|
.Include(z => z.Permission)
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(z => roles.Contains(z.UserRoleId) && z.Active)
|
||||||
|
.ToArrayAsync();
|
||||||
|
|
||||||
|
var permissions = authorizations.Select(z => z.Permission);
|
||||||
|
foreach (var permission in permissions)
|
||||||
|
{
|
||||||
|
await BuildChildrenHierarchy(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<string>> GetUserPermissionCodes(IEnumerable<int> roles)
|
||||||
|
{
|
||||||
|
var permissions = await GetUserPermissions(roles);
|
||||||
|
var codes = GetPermissionCodes(permissions);
|
||||||
|
return codes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
namespace NetworkResurrector.Api.Domain.Abstractions
|
|
||||||
{
|
|
||||||
public interface IUserService
|
|
||||||
{
|
|
||||||
bool UserIsLoggedIn { get; }
|
|
||||||
string GetUserId();
|
|
||||||
string GetUserName();
|
|
||||||
bool UserIsGuest();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NetworkResurrector.Api.Domain.Repositories
|
||||||
|
{
|
||||||
|
public interface ISecurityRepository
|
||||||
|
{
|
||||||
|
Task<IEnumerable<string>> GetUserPermissionCodes(IEnumerable<int> roles);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NetworkResurrector.Api.Application.Queries;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NetworkResurrector.Api.Controllers
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("security")]
|
||||||
|
public class SecurityController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public SecurityController(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("permissions")]
|
||||||
|
public async Task<IActionResult> GetUserPermissions([FromRoute] GetUserPermissions.Query query)
|
||||||
|
{
|
||||||
|
var result = await _mediator.Send(query);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,9 +10,7 @@ using Netmash.Infrastructure.DatabaseMigration.Constants;
|
||||||
using Netmash.Security.Authentication.Tuitio;
|
using Netmash.Security.Authentication.Tuitio;
|
||||||
using NetworkResurrector.Agent.Wrapper;
|
using NetworkResurrector.Agent.Wrapper;
|
||||||
using NetworkResurrector.Api.Application;
|
using NetworkResurrector.Api.Application;
|
||||||
using NetworkResurrector.Api.Domain.Abstractions;
|
|
||||||
using NetworkResurrector.Api.Domain.Data;
|
using NetworkResurrector.Api.Domain.Data;
|
||||||
using NetworkResurrector.Api.Services;
|
|
||||||
using NetworkResurrector.Server.Wrapper;
|
using NetworkResurrector.Server.Wrapper;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
@ -28,9 +26,6 @@ namespace NetworkResurrector.Api.Extensions
|
||||||
// Add basic authentication
|
// Add basic authentication
|
||||||
services.AddTuitioAuthentication(configuration.GetSection("Tuitio")["BaseAddress"]);
|
services.AddTuitioAuthentication(configuration.GetSection("Tuitio")["BaseAddress"]);
|
||||||
|
|
||||||
services.AddHttpContextAccessor();
|
|
||||||
services.AddScoped<IUserService, UserService>();
|
|
||||||
|
|
||||||
// MediatR
|
// MediatR
|
||||||
services.AddMediatR(typeof(Application.Queries.GetMachines).Assembly);
|
services.AddMediatR(typeof(Application.Queries.GetMachines).Assembly);
|
||||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
|
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
<PackageReference Include="NBB.Messaging.Nats" Version="$(NBBPackageVersion)" />
|
<PackageReference Include="NBB.Messaging.Nats" Version="$(NBBPackageVersion)" />
|
||||||
<PackageReference Include="Netmash.Extensions.Swagger" Version="$(NetmashExtensionsSwaggerPackageVersion)" />
|
<PackageReference Include="Netmash.Extensions.Swagger" Version="$(NetmashExtensionsSwaggerPackageVersion)" />
|
||||||
<PackageReference Include="Netmash.Infrastructure.DatabaseMigration" Version="$(NetmashDatabaseMigrationPackageVersion)" />
|
<PackageReference Include="Netmash.Infrastructure.DatabaseMigration" Version="$(NetmashDatabaseMigrationPackageVersion)" />
|
||||||
<PackageReference Include="Netmash.Security.Authentication.Tuitio" Version="$(NetmashTuitioAuthenticationPackageVersion)" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="$(SerilogPackageVersion)" />
|
<PackageReference Include="Serilog.AspNetCore" Version="$(SerilogPackageVersion)" />
|
||||||
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="$(SerilogSinksMSSqlServerPackageVersion)" />
|
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="$(SerilogSinksMSSqlServerPackageVersion)" />
|
||||||
<PackageReference Include="Serilog.Sinks.Seq" Version="$(SerilogSinksSeqPackageVersion)" />
|
<PackageReference Include="Serilog.Sinks.Seq" Version="$(SerilogSinksSeqPackageVersion)" />
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using NetworkResurrector.Api.Domain.Abstractions;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace NetworkResurrector.Api.Services
|
|
||||||
{
|
|
||||||
public class UserService : IUserService
|
|
||||||
{
|
|
||||||
private readonly IHttpContextAccessor _httpAccessor;
|
|
||||||
|
|
||||||
public UserService(IHttpContextAccessor httpAccessor)
|
|
||||||
{
|
|
||||||
_httpAccessor = httpAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UserIsLoggedIn => _httpAccessor.HttpContext.User != null;
|
|
||||||
|
|
||||||
public string GetUserId()
|
|
||||||
{
|
|
||||||
var userId = _httpAccessor.HttpContext.User?.Claims.FirstOrDefault(z => z.Type == ClaimTypes.NameIdentifier)?.Value;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(userId))
|
|
||||||
throw new Exception("User id could not be retrieved from claims.");
|
|
||||||
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetUserName()
|
|
||||||
{
|
|
||||||
var userName = _httpAccessor.HttpContext.User?.Claims.FirstOrDefault(z => z.Type == ClaimTypes.Name)?.Value;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(userName))
|
|
||||||
throw new Exception("User name could not be retrieved from claims.");
|
|
||||||
|
|
||||||
return userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UserIsGuest()
|
|
||||||
{
|
|
||||||
var userIsGuest = _httpAccessor.HttpContext.User?.Claims.FirstOrDefault(z => z.Type == Netmash.Security.Authentication.Tuitio.Constants.ClaimTypes.IsGuestUser)?.Value;
|
|
||||||
return !string.IsNullOrEmpty(userIsGuest) && bool.TrueString == userIsGuest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue