Skip to content

Commit b3b8317

Browse files
Added option to set a temporary user id in ICurrentUserProvider
1 parent 59314fa commit b3b8317

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

src/DotNetElements.AppFramework.Abstractions/Auth/ICurrentUserProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
public interface ICurrentUserProvider
44
{
55
Guid GetCurrentUserId();
6+
void SetTemporaryUserId(Guid userId);
67
}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System.Security.Claims;
22
using DotNetElements.AppFramework.Abstractions.Auth;
3+
using DotNetElements.Core.Extensions;
34
using Microsoft.AspNetCore.Http;
45

56
namespace DotNetElements.AppFramework.AspNet;
67

78
public class CurrentUserProvider : ICurrentUserProvider
89
{
10+
private Guid? temporaryUserId;
11+
912
private readonly IHttpContextAccessor contextAccessor;
1013

1114
public CurrentUserProvider(IHttpContextAccessor contextAccessor)
@@ -15,12 +18,16 @@ public CurrentUserProvider(IHttpContextAccessor contextAccessor)
1518

1619
public Guid GetCurrentUserId()
1720
{
18-
string? userId = contextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier);
21+
if (temporaryUserId is not null)
22+
return temporaryUserId.Value;
23+
24+
ArgumentNullException.ThrowIfNull(contextAccessor.HttpContext);
1925

20-
// todo better error handling
21-
if (userId is null)
22-
throw new ArgumentNullException(nameof(userId));
26+
return contextAccessor.HttpContext.User.GetRequiredValue<Guid>(ClaimTypes.NameIdentifier);
27+
}
2328

24-
return new Guid(userId);
29+
public void SetTemporaryUserId(Guid userId)
30+
{
31+
temporaryUserId = userId;
2532
}
2633
}

src/DotNetElements.AppFramework.Development/FakeCurrentUserProvider.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace DotNetElements.AppFramework.Development;
44

55
public sealed class FakeCurrentUserProvider : ICurrentUserProvider
66
{
7+
private Guid? temporaryUserId;
8+
79
private readonly Guid fakeUserId;
810

911
public FakeCurrentUserProvider(Guid fakeUserId)
@@ -13,6 +15,14 @@ public FakeCurrentUserProvider(Guid fakeUserId)
1315

1416
public Guid GetCurrentUserId()
1517
{
18+
if (temporaryUserId is not null)
19+
return temporaryUserId.Value;
20+
1621
return fakeUserId;
1722
}
23+
24+
public void SetTemporaryUserId(Guid userId)
25+
{
26+
temporaryUserId = userId;
27+
}
1828
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Security.Claims;
2+
3+
namespace DotNetElements.Core.Extensions;
4+
5+
/// <summary>
6+
/// Claims related extensions for <see cref="ClaimsPrincipal"/>.
7+
/// </summary>
8+
public static class PrincipalExtensions
9+
{
10+
/// <summary>
11+
/// Retrieves a required claim value from the given <see cref="ClaimsPrincipal"/>.
12+
/// </summary>
13+
/// <param name="principal">The <see cref="ClaimsPrincipal"/> from which to retrieve the claim value.</param>
14+
/// <param name="claimType">The type of the claim to retrieve.</param>
15+
/// <returns>The value of the specified claim.</returns>
16+
/// <exception cref="InvalidOperationException">Thrown if the specified claim type is not present in the <paramref name="principal"/>.</exception>
17+
public static string GetRequiredValue(this ClaimsPrincipal principal, string claimType)
18+
{
19+
Claim? claim = principal.FindFirst(claimType);
20+
21+
if (claim is null)
22+
throw new InvalidOperationException($"Claim '{claimType}' is required but not present in the principal.");
23+
24+
return claim.Value;
25+
}
26+
27+
/// <summary>
28+
/// Retrieves and parses a required claim value from the specified <see cref="ClaimsPrincipal"/>.
29+
/// </summary>
30+
/// <typeparam name="T">The type to which the claim value should be parsed. Must implement <see cref="IParsable{T}"/>.</typeparam>
31+
/// <param name="principal">The <see cref="ClaimsPrincipal"/> from which to retrieve the claim.</param>
32+
/// <param name="claimType">The type of the claim to retrieve.</param>
33+
/// <returns>The parsed claim value of type <typeparamref name="T"/>.</returns>
34+
/// <exception cref="InvalidOperationException">Thrown if the claim of the specified <paramref name="claimType"/> is not present in the <paramref
35+
/// name="principal"/> or if the claim value cannot be parsed to type <typeparamref name="T"/>.</exception>
36+
public static T GetRequiredValue<T>(this ClaimsPrincipal principal, string claimType)
37+
where T : IParsable<T>
38+
{
39+
Claim? claim = principal.FindFirst(claimType);
40+
41+
if (claim is null)
42+
throw new InvalidOperationException($"Claim '{claimType}' is required but not present in the principal.");
43+
44+
if (!T.TryParse(claim.Value, null, out T? value))
45+
throw new InvalidOperationException($"Claim '{claimType}' has an invalid value: '{claim.Value}'.");
46+
47+
return value;
48+
}
49+
}

0 commit comments

Comments
 (0)