Skip to content

Commit 876cfab

Browse files
committed
Completed EFCore Authorization Store
1 parent 9b0dbf7 commit 876cfab

File tree

18 files changed

+715
-15
lines changed

18 files changed

+715
-15
lines changed

UltimateAuth.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
</Folder>
1515
<Project Path="src/authentication/CodeBeam.UltimateAuth.Authentication.InMemory/CodeBeam.UltimateAuth.Authentication.InMemory.csproj" Id="bd87e254-0565-4fc5-950d-ee5bbb416079" />
1616
<Project Path="src/authorization/CodeBeam.UltimateAuth.Authorization.Contracts/CodeBeam.UltimateAuth.Authorization.Contracts.csproj" Id="40a23002-f885-42a8-bdd9-fd962ab28742" />
17+
<Project Path="src/authorization/CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore/CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore.csproj" Id="8572d1e8-db32-42a1-b61c-e8805e59c019" />
1718
<Project Path="src/authorization/CodeBeam.UltimateAuth.Authorization.InMemory/CodeBeam.UltimateAuth.Authorization.InMemory.csproj" Id="a1e6d007-bdc0-4574-b549-ec863757edd3" />
1819
<Project Path="src/authorization/CodeBeam.UltimateAuth.Authorization.Reference/CodeBeam.UltimateAuth.Authorization.Reference.csproj" Id="84b784d0-bb48-406a-a0d1-c600da667597" />
1920
<Project Path="src/authorization/CodeBeam.UltimateAuth.Authorization/CodeBeam.UltimateAuth.Authorization.csproj" Id="28b1d647-fb0b-4cc3-8503-2680c4a9b28f" />

src/authorization/CodeBeam.UltimateAuth.Authorization.Contracts/Domain/Permission.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ public static Permission From(string value)
1616
public bool IsPrefix => Value.EndsWith(".*");
1717

1818
public override string ToString() => Value;
19+
20+
public static implicit operator string(Permission p) => p.Value;
1921
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using System.Runtime.CompilerServices;
2+
3+
[assembly: InternalsVisibleTo("CodeBeam.UltimateAuth.Tests.Unit")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8+
<NoWarn>$(NoWarn);1591</NoWarn>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\..\CodeBeam.UltimateAuth.Core\CodeBeam.UltimateAuth.Core.csproj" />
13+
<ProjectReference Include="..\..\persistence\CodeBeam.UltimateAuth.EntityFrameworkCore.Abstractions\CodeBeam.UltimateAuth.EntityFrameworkCore.Abstractions.csproj" />
14+
<ProjectReference Include="..\CodeBeam.UltimateAuth.Authorization.Contracts\CodeBeam.UltimateAuth.Authorization.Contracts.csproj" />
15+
<ProjectReference Include="..\CodeBeam.UltimateAuth.Authorization.InMemory\CodeBeam.UltimateAuth.Authorization.InMemory.csproj" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using CodeBeam.UltimateAuth.Authorization.Contracts;
2+
using CodeBeam.UltimateAuth.Core.Domain;
3+
using CodeBeam.UltimateAuth.Core.MultiTenancy;
4+
using Microsoft.EntityFrameworkCore;
5+
6+
namespace CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore;
7+
8+
internal sealed class UAuthAuthorizationDbContext : DbContext
9+
{
10+
public DbSet<RoleProjection> Roles => Set<RoleProjection>();
11+
public DbSet<RolePermissionProjection> RolePermissions => Set<RolePermissionProjection>();
12+
public DbSet<UserRoleProjection> UserRoles => Set<UserRoleProjection>();
13+
14+
private readonly TenantContext _tenant;
15+
16+
public UAuthAuthorizationDbContext(DbContextOptions<UAuthAuthorizationDbContext> options, TenantContext tenant)
17+
: base(options)
18+
{
19+
_tenant = tenant;
20+
}
21+
22+
protected override void OnModelCreating(ModelBuilder b)
23+
{
24+
ConfigureRole(b);
25+
ConfigureRolePermission(b);
26+
ConfigureUserRole(b);
27+
}
28+
29+
private void ConfigureRole(ModelBuilder b)
30+
{
31+
b.Entity<RoleProjection>(e =>
32+
{
33+
e.HasKey(x => x.Id);
34+
35+
e.Property(x => x.Version)
36+
.IsConcurrencyToken();
37+
38+
e.Property(x => x.Tenant)
39+
.HasConversion(
40+
v => v.Value,
41+
v => TenantKey.FromInternal(v))
42+
.HasMaxLength(128)
43+
.IsRequired();
44+
45+
e.Property(x => x.Id)
46+
.HasConversion(
47+
v => v.Value,
48+
v => RoleId.From(v))
49+
.IsRequired();
50+
51+
e.Property(x => x.Name)
52+
.HasMaxLength(128)
53+
.IsRequired();
54+
55+
e.Property(x => x.NormalizedName)
56+
.HasMaxLength(128)
57+
.IsRequired();
58+
59+
e.Property(x => x.CreatedAt)
60+
.IsRequired();
61+
62+
e.HasIndex(x => new { x.Tenant, x.Id }).IsUnique();
63+
e.HasIndex(x => new { x.Tenant, x.NormalizedName }).IsUnique();
64+
65+
e.HasQueryFilter(x => _tenant.IsGlobal || x.Tenant == _tenant.Tenant);
66+
});
67+
}
68+
69+
private void ConfigureRolePermission(ModelBuilder b)
70+
{
71+
b.Entity<RolePermissionProjection>(e =>
72+
{
73+
e.HasKey(x => new { x.Tenant, x.RoleId, x.Permission });
74+
75+
e.Property(x => x.Tenant)
76+
.HasConversion(
77+
v => v.Value,
78+
v => TenantKey.FromInternal(v))
79+
.HasMaxLength(128)
80+
.IsRequired();
81+
82+
e.Property(x => x.RoleId)
83+
.HasConversion(
84+
v => v.Value,
85+
v => RoleId.From(v))
86+
.IsRequired();
87+
88+
e.Property(x => x.Permission)
89+
.HasMaxLength(256)
90+
.IsRequired();
91+
92+
e.HasIndex(x => new { x.Tenant, x.RoleId });
93+
e.HasIndex(x => new { x.Tenant, x.Permission });
94+
95+
e.HasQueryFilter(x => _tenant.IsGlobal || x.Tenant == _tenant.Tenant);
96+
});
97+
}
98+
99+
private void ConfigureUserRole(ModelBuilder b)
100+
{
101+
b.Entity<UserRoleProjection>(e =>
102+
{
103+
e.HasKey(x => new { x.Tenant, x.UserKey, x.RoleId });
104+
105+
e.Property(x => x.Tenant)
106+
.HasConversion(
107+
v => v.Value,
108+
v => TenantKey.FromInternal(v))
109+
.HasMaxLength(128)
110+
.IsRequired();
111+
112+
e.Property(x => x.UserKey)
113+
.HasConversion(
114+
v => v.Value,
115+
v => UserKey.FromString(v))
116+
.HasMaxLength(128)
117+
.IsRequired();
118+
119+
e.Property(x => x.RoleId)
120+
.HasConversion(
121+
v => v.Value,
122+
v => RoleId.From(v))
123+
.IsRequired();
124+
125+
e.Property(x => x.AssignedAt)
126+
.IsRequired();
127+
128+
e.HasIndex(x => new { x.Tenant, x.UserKey });
129+
e.HasIndex(x => new { x.Tenant, x.RoleId });
130+
131+
e.HasQueryFilter(x => _tenant.IsGlobal || x.Tenant == _tenant.Tenant);
132+
});
133+
}
134+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.Extensions.DependencyInjection;
3+
4+
namespace CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore.Extensions;
5+
6+
public static class ServiceCollectionExtensions
7+
{
8+
public static IServiceCollection AddUltimateAuthEntityFrameworkCoreAuthorization(this IServiceCollection services, Action<DbContextOptionsBuilder> configureDb)
9+
{
10+
services.AddDbContextPool<UAuthAuthorizationDbContext>(configureDb);
11+
services.AddScoped<IRoleStore, EfCoreRoleStore>();
12+
services.AddScoped<IUserRoleStore, EfCoreUserRoleStore>();
13+
return services;
14+
}
15+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using CodeBeam.UltimateAuth.Authorization;
2+
using CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore;
3+
4+
internal static class RoleMapper
5+
{
6+
public static Role ToDomain(RoleProjection projection, IEnumerable<RolePermissionProjection> permissionEntities)
7+
{
8+
var permissions = permissionEntities.Select(RolePermissionMapper.ToDomain);
9+
10+
return Role.FromProjection(
11+
projection.Id,
12+
projection.Tenant,
13+
projection.Name,
14+
permissions,
15+
projection.CreatedAt,
16+
projection.UpdatedAt,
17+
projection.DeletedAt,
18+
projection.Version);
19+
}
20+
21+
public static RoleProjection ToProjection(Role role)
22+
{
23+
return new RoleProjection
24+
{
25+
Id = role.Id,
26+
Tenant = role.Tenant,
27+
Name = role.Name,
28+
NormalizedName = role.NormalizedName,
29+
CreatedAt = role.CreatedAt,
30+
UpdatedAt = role.UpdatedAt,
31+
DeletedAt = role.DeletedAt,
32+
Version = role.Version
33+
};
34+
}
35+
36+
public static void UpdateProjection(Role role, RoleProjection entity)
37+
{
38+
entity.Name = role.Name;
39+
entity.NormalizedName = role.NormalizedName;
40+
entity.UpdatedAt = role.UpdatedAt;
41+
}
42+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using CodeBeam.UltimateAuth.Authorization.Contracts;
2+
using CodeBeam.UltimateAuth.Authorization.Domain;
3+
using CodeBeam.UltimateAuth.Core.MultiTenancy;
4+
5+
namespace CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore;
6+
7+
internal static class RolePermissionMapper
8+
{
9+
public static RolePermissionProjection ToProjection(TenantKey tenant, RoleId roleId, Permission permission)
10+
{
11+
return new RolePermissionProjection
12+
{
13+
Tenant = tenant,
14+
RoleId = roleId,
15+
Permission = permission.Value
16+
};
17+
}
18+
19+
public static Permission ToDomain(RolePermissionProjection projection)
20+
{
21+
return Permission.From(projection.Permission);
22+
}
23+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore;
2+
3+
internal static class UserRoleMapper
4+
{
5+
public static UserRole ToDomain(UserRoleProjection projection)
6+
{
7+
return new UserRole
8+
{
9+
Tenant = projection.Tenant,
10+
UserKey = projection.UserKey,
11+
RoleId = projection.RoleId,
12+
AssignedAt = projection.AssignedAt
13+
};
14+
}
15+
16+
public static UserRoleProjection ToProjection(UserRole role)
17+
{
18+
return new UserRoleProjection
19+
{
20+
Tenant = role.Tenant,
21+
UserKey = role.UserKey,
22+
RoleId = role.RoleId,
23+
AssignedAt = role.AssignedAt
24+
};
25+
}
26+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using CodeBeam.UltimateAuth.Authorization.Contracts;
2+
using CodeBeam.UltimateAuth.Core.MultiTenancy;
3+
4+
namespace CodeBeam.UltimateAuth.Authorization.EntityFrameworkCore;
5+
6+
internal sealed class RolePermissionProjection
7+
{
8+
public TenantKey Tenant { get; set; }
9+
10+
public RoleId RoleId { get; set; }
11+
12+
public string Permission { get; set; } = default!;
13+
}

0 commit comments

Comments
 (0)