Skip to content

Commit 9919886

Browse files
committed
Complete UAuthState
1 parent 3f99f4a commit 9919886

13 files changed

Lines changed: 126 additions & 20 deletions

File tree

samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Pages/Home.razor

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@page "/home"
2+
@using System.Security.Claims
23
@attribute [Authorize]
34

45
@inject AuthenticationStateProvider AuthProvider
@@ -33,6 +34,7 @@
3334
<MudText>Tenant: @AuthState?.Identity?.Tenant.Value</MudText>
3435
<MudText>Authenticated At: @AuthState?.Identity?.AuthenticatedAt</MudText>
3536
<MudText>Last Validated At: @AuthState?.LastValidatedAt</MudText>
37+
<MudText>Is Admin: @AuthState.IsInRole("Admin")</MudText>
3638
<MudText>Roles: @string.Join(", ", AuthState.Claims.Roles)</MudText>
3739
</MudPaper>
3840
</MudItem>

samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Pages/Home.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="StateHasChanged">StateHasChanged</MudButton>
4949
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="RefreshAuthState">Refresh Auth State</MudButton>
5050
<MudText>State of Authentication:</MudText>
51-
<MudText>From UltimateAuth: @(Auth?.IsAuthenticated == true ? "Authenticated" : "Not Authenticated") - UserId:@(Auth?.UserKey)</MudText>
51+
<MudText>From UltimateAuth: @(Auth?.IsAuthenticated == true ? "Authenticated" : "Not Authenticated") - UserId:@(Auth?.Identity?.UserKey)</MudText>
5252
<MudText>From ASPNET Core: @(_authState?.User?.Identity?.IsAuthenticated == true ? "Authenticated" : "Not Authenticated") - UserId:@(_authState?.User?.Identity?.Name)</MudText>
5353
<AuthorizeView>
5454
<Authorized>

src/CodeBeam.UltimateAuth.Client/Authentication/UAuthState.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ internal void Clear()
7272
Changed?.Invoke(UAuthStateChangeReason.Cleared);
7373
}
7474

75+
public bool IsInRole(string role) => IsAuthenticated && Claims.IsInRole(role);
76+
77+
public bool HasPermission(string permission) => IsAuthenticated && Claims.HasPermission(permission);
78+
79+
public bool HasClaim(string type, string value) => IsAuthenticated && Claims.HasValue(type, value);
80+
81+
public string? GetClaim(string type) => IsAuthenticated ? Claims.Get(type) : null;
82+
7583
/// <summary>
7684
/// Creates a ClaimsPrincipal view for ASP.NET / Blazor integration.
7785
/// </summary>

src/CodeBeam.UltimateAuth.Core/Domain/Session/AuthSessionId.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
namespace CodeBeam.UltimateAuth.Core.Domain;
1+
using CodeBeam.UltimateAuth.Core.Infrastructure;
2+
using System.Text.Json.Serialization;
3+
4+
namespace CodeBeam.UltimateAuth.Core.Domain;
25

36
// AuthSessionId is a opaque token, because it's more sensitive data. SessionChainId and SessionRootId are Guid.
7+
[JsonConverter(typeof(AuthSessionIdJsonConverter))]
48
public readonly record struct AuthSessionId
59
{
610
public string Value { get; }

src/CodeBeam.UltimateAuth.Core/Domain/Session/SessionChainId.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
namespace CodeBeam.UltimateAuth.Core.Domain;
1+
using CodeBeam.UltimateAuth.Core.Infrastructure;
2+
using System.Text.Json.Serialization;
23

4+
namespace CodeBeam.UltimateAuth.Core.Domain;
5+
6+
[JsonConverter(typeof(SessionChainIdJsonConverter))]
37
public readonly record struct SessionChainId(Guid Value)
48
{
59
public static SessionChainId New() => new(Guid.NewGuid());

src/CodeBeam.UltimateAuth.Core/Domain/Session/SessionRootId.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
namespace CodeBeam.UltimateAuth.Core.Domain;
1+
using CodeBeam.UltimateAuth.Core.Infrastructure;
2+
using System.Text.Json.Serialization;
23

4+
namespace CodeBeam.UltimateAuth.Core.Domain;
5+
6+
[JsonConverter(typeof(SessionRootIdJsonConverter))]
37
public readonly record struct SessionRootId(Guid Value)
48
{
59
public static SessionRootId New() => new(Guid.NewGuid());

src/CodeBeam.UltimateAuth.Core/Extensions/ClaimsSnapshotExtensions.cs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using CodeBeam.UltimateAuth.Core.Domain;
1+
using CodeBeam.UltimateAuth.Core.Contracts;
2+
using CodeBeam.UltimateAuth.Core.Domain;
23
using System.Security.Claims;
34

45
namespace CodeBeam.UltimateAuth.Core.Extensions;
@@ -19,25 +20,19 @@ public static ClaimsPrincipal ToClaimsPrincipal(this ClaimsSnapshot snapshot, st
1920
return new ClaimsPrincipal(identity);
2021
}
2122

22-
public static ClaimsPrincipal ToClaimsPrincipal(this ClaimsSnapshot snapshot, UserKey? userKey, string authenticationType)
23+
public static ClaimsPrincipal ToClaimsPrincipal(this AuthStateSnapshot snapshot, string authenticationType)
2324
{
24-
if (snapshot == null)
25-
return new ClaimsPrincipal(new ClaimsIdentity());
25+
var claims = snapshot.Claims.ToClaims().ToList();
2626

27-
var claims = snapshot.Claims.SelectMany(kv => kv.Value.Select(v => new Claim(kv.Key, v))).ToList();
27+
claims.Add(new Claim(ClaimTypes.NameIdentifier, snapshot.Identity.UserKey.Value));
2828

29-
if (userKey is not null)
30-
{
31-
var value = userKey.Value.ToString();
32-
claims.Add(new Claim(ClaimTypes.Name, value));
33-
claims.Add(new Claim(ClaimTypes.NameIdentifier, value));
34-
}
29+
if (!string.IsNullOrWhiteSpace(snapshot.Identity.PrimaryUserName))
30+
claims.Add(new Claim(ClaimTypes.Name, snapshot.Identity.PrimaryUserName));
3531

36-
var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
37-
return new ClaimsPrincipal(identity);
32+
var ci = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
33+
return new ClaimsPrincipal(ci);
3834
}
3935

40-
4136
/// <summary>
4237
/// Converts an ASP.NET Core ClaimsPrincipal into a ClaimsSnapshot.
4338
/// </summary>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using CodeBeam.UltimateAuth.Core.Domain;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
4+
5+
namespace CodeBeam.UltimateAuth.Core.Infrastructure;
6+
7+
public sealed class AuthSessionIdJsonConverter : JsonConverter<AuthSessionId>
8+
{
9+
public override AuthSessionId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
10+
{
11+
if (reader.TokenType != JsonTokenType.String)
12+
throw new JsonException("AuthSessionId must be a string.");
13+
14+
var value = reader.GetString();
15+
16+
if (!AuthSessionId.TryCreate(value, out var id))
17+
throw new JsonException($"Invalid AuthSessionId value: '{value}'");
18+
19+
return id;
20+
}
21+
22+
public override void Write(Utf8JsonWriter writer, AuthSessionId value, JsonSerializerOptions options)
23+
{
24+
writer.WriteStringValue(value.Value);
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using CodeBeam.UltimateAuth.Core.Domain;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
4+
5+
namespace CodeBeam.UltimateAuth.Core.Infrastructure;
6+
7+
public sealed class SessionChainIdJsonConverter : JsonConverter<SessionChainId>
8+
{
9+
public override SessionChainId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
10+
{
11+
if (reader.TokenType != JsonTokenType.String)
12+
throw new JsonException("SessionChainId must be a string.");
13+
14+
var raw = reader.GetString();
15+
16+
if (!SessionChainId.TryCreate(raw!, out var id))
17+
throw new JsonException($"Invalid SessionChainId value: '{raw}'");
18+
19+
return id;
20+
}
21+
22+
public override void Write(Utf8JsonWriter writer, SessionChainId value, JsonSerializerOptions options)
23+
{
24+
writer.WriteStringValue(value.Value.ToString("N"));
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using CodeBeam.UltimateAuth.Core.Domain;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
4+
5+
namespace CodeBeam.UltimateAuth.Core.Infrastructure;
6+
7+
public sealed class SessionRootIdJsonConverter : JsonConverter<SessionRootId>
8+
{
9+
public override SessionRootId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
10+
{
11+
if (reader.TokenType != JsonTokenType.String)
12+
throw new JsonException("SessionChainId must be a string.");
13+
14+
var raw = reader.GetString();
15+
16+
if (!SessionRootId.TryCreate(raw!, out var id))
17+
throw new JsonException($"Invalid SessionChainId value: '{raw}'");
18+
19+
return id;
20+
}
21+
22+
public override void Write(Utf8JsonWriter writer, SessionRootId value, JsonSerializerOptions options)
23+
{
24+
writer.WriteStringValue(value.Value.ToString("N"));
25+
}
26+
}

0 commit comments

Comments
 (0)