Cayaqui.MPS.Authorization
0.1.0
dotnet add package Cayaqui.MPS.Authorization --version 0.1.0
NuGet\Install-Package Cayaqui.MPS.Authorization -Version 0.1.0
<PackageReference Include="Cayaqui.MPS.Authorization" Version="0.1.0" />
<PackageVersion Include="Cayaqui.MPS.Authorization" Version="0.1.0" />
<PackageReference Include="Cayaqui.MPS.Authorization" />
paket add Cayaqui.MPS.Authorization --version 0.1.0
#r "nuget: Cayaqui.MPS.Authorization, 0.1.0"
#:package Cayaqui.MPS.Authorization@0.1.0
#addin nuget:?package=Cayaqui.MPS.Authorization&version=0.1.0
#tool nuget:?package=Cayaqui.MPS.Authorization&version=0.1.0
Cayaqui.MPS.Authorization
Business authorization layer for MPS Blazor apps (.NET 10 Blazor WebApp Interactive Server).
What's included
| Type | Description |
|---|---|
AppUser |
Application user entity (Email, DisplayName, PhotoUrl, ExternalId for Entra ID) |
UserRole |
Role assignment: (UserId, Role, ProjectId?) — null ProjectId = global scope |
MpsRoles |
Role name constants: SuperAdmin, Admin, ProjectManager, ProjectController, ProjectEngineer, ProjectViewer |
MpsPermissions |
Granular permission constants: Resource.Action (e.g. Projects.Edit, Budget.Approve) |
IMpsCurrentUser |
Extended current user: IsAuthenticated, IsSuperAdmin, HasPermission(), IsInRole() |
IMpsAuthorizationService |
Load and evaluate role assignments from DB |
IMpsUserService |
User CRUD + role assignment |
AuthorizationDbContext |
EF Core context: Users + UserRoles tables |
MpsAuthorizeView |
Blazor component: conditionally renders content based on permission/role |
MpsAccessDenied |
Blazor component: access-denied page with back button |
Quick start
// Program.cs
using MPS.Authorization.Extensions;
builder.Services.AddMpsAuthorization(o =>
o.UseSqlServer(connectionString)); // or UseInMemoryDatabase for dev
// Register your IMpsCurrentUser implementation (Scoped)
builder.Services.AddScoped<IMpsCurrentUser, YourCurrentUser>();
MpsAuthorizeView
@using MPS.Authorization.Domain
<MpsAuthorizeView Permission="@MpsPermissions.Budget.Approve" ProjectId="@projectId">
<button>Aprobar Presupuesto</button>
</MpsAuthorizeView>
<MpsAuthorizeView Role="@MpsRoles.ProjectManager" ProjectId="@projectId">
<Authorized>
<button>Editar</button>
</Authorized>
<NotAuthorized>
<span>Solo lectura</span>
</NotAuthorized>
</MpsAuthorizeView>
Implementing IMpsCurrentUser
// Scoped — loaded once per Blazor circuit
public sealed class CurrentUser : IMpsCurrentUser
{
private readonly IMpsAuthorizationService _authService;
private IReadOnlyList<UserRoleAssignment>? _assignments;
public CurrentUser(IHttpContextAccessor http, IMpsAuthorizationService authService)
{
_authService = authService;
var claims = http.HttpContext?.User;
IsAuthenticated = claims?.Identity?.IsAuthenticated ?? false;
Id = IsAuthenticated ? Guid.Parse(claims!.FindFirstValue(ClaimTypes.NameIdentifier)!) : null;
Email = claims?.FindFirstValue(ClaimTypes.Email);
DisplayName = claims?.FindFirstValue("name");
}
public Guid? Id { get; }
public string? Email { get; }
public string? DisplayName { get; }
public string? PhotoUrl { get; set; } // set after photo URL is resolved
public bool IsAuthenticated { get; }
public bool IsSuperAdmin => RoleAssignments.Any(r => r.Role == MpsRoles.SuperAdmin);
public IReadOnlyList<UserRoleAssignment> RoleAssignments =>
_assignments ??= Id.HasValue
? _authService.GetUserRolesAsync(Id.Value).GetAwaiter().GetResult()
: [];
public bool IsInRole(string role, Guid? projectId = null) =>
IsSuperAdmin || RoleAssignments.Any(r =>
r.Role == role && (r.ProjectId is null || r.ProjectId == projectId));
public bool HasPermission(string permission, Guid? projectId = null) =>
IsAuthenticated && _authService.HasPermission(RoleAssignments, permission, projectId);
}
Role → Permission matrix
| Permission | SuperAdmin | Admin | ProjectManager | ProjectController | ProjectEngineer | ProjectViewer |
|---|---|---|---|---|---|---|
| Users.ManageRoles | ✓ | ✓ | ||||
| Projects.Create/Delete | ✓ | ✓ | ||||
| Budget.Approve/Baseline | ✓ | ✓ | ✓ | |||
| Evm.Publish | ✓ | ✓ | ✓ | |||
| Schedule.Publish | ✓ | ✓ | ✓ | |||
| ChangeOrders.Approve | ✓ | ✓ | ✓ | |||
| View (all resources) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Auth models
This package is auth-provider agnostic. Two deployment models are supported:
Entra ID: Admin pre-registers email → user logs in with Entra → IMpsUserService.FindByEmailAsync provisions the record → photo downloaded via Graph API and stored via Cayaqui.MPS.Storage.
Local auth: Standard ASP.NET Core Identity with MFA (Email OTP / SMS OTP / TOTP). Same AppUser entity extended with Identity columns.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cayaqui.MPS.Abstractions (>= 0.1.0)
- Microsoft.AspNetCore.Components.Web (>= 10.0.7)
- Microsoft.EntityFrameworkCore (>= 10.0.7)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 106 | 6/1/2026 |
v0.1.0 — Initial release. AppUser, UserRole, MpsRoles, MpsPermissions, IMpsCurrentUser, MpsAuthorizeView, MpsAccessDenied, AuthorizationDbContext, AddMpsAuthorization() DI extension.