-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathPasswordlessApiEndpointRouteBuilderExtensions.cs
136 lines (121 loc) · 5.44 KB
/
PasswordlessApiEndpointRouteBuilderExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Diagnostics.CodeAnalysis;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Passwordless.AspNetCore.Services;
namespace Passwordless.AspNetCore;
/// <summary>
/// Provides extension methods for <see cref="IEndpointRouteBuilder" /> to map Passwordless endpoints.
/// </summary>
public static class PasswordlessApiEndpointRouteBuilderExtensions
{
/// <summary>
///
/// </summary>
[RequiresUnreferencedCode("This method is incompatible with assembly trimming.")]
[RequiresDynamicCode("This method is incompatible with native AOT compilation.")]
public static PasswordlessEndpointConventionBuilder MapPasswordless(this IEndpointRouteBuilder endpoints, bool enableRegisterEndpoint = false)
{
// TODO: When a custom register body isn't passed in, we can make a reasonable assumption
// about what each endpoint produces and we can build on those.
var builder = endpoints.MapPasswordless(new PasswordlessEndpointOptions(enableRegisterEndpoint));
return builder;
}
/// <summary>
///
/// </summary>
[RequiresUnreferencedCode("This method is incompatible with assembly trimming.")]
[RequiresDynamicCode("This method is incompatible with native AOT compilation.")]
public static PasswordlessEndpointConventionBuilder MapPasswordless(this IEndpointRouteBuilder endpoints, PasswordlessEndpointOptions endpointOptions)
{
return endpoints.MapPasswordless<PasswordlessRegisterRequest>(endpointOptions);
}
/// <summary>
///
/// </summary>
[RequiresUnreferencedCode("This method is incompatible with assembly trimming.")]
[RequiresDynamicCode("This method is incompatible with native AOT compilation.")]
public static PasswordlessEndpointConventionBuilder MapPasswordless<TRegisterBody>(this IEndpointRouteBuilder endpoints)
{
return endpoints.MapPasswordless<PasswordlessRegisterRequest>(new PasswordlessEndpointOptions(enableRegisterEndpoint: true));
}
/// <summary>
///
/// </summary>
[RequiresUnreferencedCode("This method is incompatible with assembly trimming.")]
[RequiresDynamicCode("This method is incompatible with native AOT compilation.")]
public static PasswordlessEndpointConventionBuilder MapPasswordless<TRegisterBody>(this IEndpointRouteBuilder endpoints, PasswordlessEndpointOptions endpointOptions)
{
var routeGroup = endpoints
.MapGroup(endpointOptions.GroupPrefix)
.WithGroupName("Passwordless");
static async Task<IResult> PasswordlessRegister(
TRegisterBody registerRequest,
IPasswordlessService<TRegisterBody> passwordlessService,
CancellationToken cancellationToken)
{
return await passwordlessService.RegisterUserAsync(registerRequest, cancellationToken);
}
RouteHandlerBuilder? registerRouteHandler = null;
if (endpointOptions.RegisterPath is not null)
{
registerRouteHandler = routeGroup.Map(endpointOptions.RegisterPath, PasswordlessRegister);
}
static async Task<IResult> PasswordlessLogin(
PasswordlessLoginRequest loginRequest,
IPasswordlessService<TRegisterBody> passwordlessService,
CancellationToken cancellationToken)
{
return await passwordlessService.LoginUserAsync(loginRequest, cancellationToken);
}
RouteHandlerBuilder? loginRouteHandler = null;
if (endpointOptions.LoginPath is not null)
{
loginRouteHandler = routeGroup.MapPost(endpointOptions.LoginPath, PasswordlessLogin);
}
static async Task<IResult> PasswordlessAddCredential(
IPasswordlessService<TRegisterBody> passwordlessService,
PasswordlessAddCredentialRequest request,
ClaimsPrincipal claimsPrincipal,
CancellationToken cancellationToken)
{
return await passwordlessService.AddCredentialAsync(request, claimsPrincipal, cancellationToken);
}
RouteHandlerBuilder? addCredentialRouteHandler = null;
if (endpointOptions.AddCredentialPath is not null)
{
addCredentialRouteHandler = routeGroup.MapPost(endpointOptions.AddCredentialPath, PasswordlessAddCredential);
// Should we require authorization?
}
return new PasswordlessEndpointConventionBuilder(routeGroup,
loginRouteHandler,
registerRouteHandler,
addCredentialRouteHandler);
}
}
public sealed class PasswordlessEndpointConventionBuilder : IEndpointConventionBuilder
{
private readonly RouteGroupBuilder _groupBuilder;
public RouteHandlerBuilder? LoginRoute { get; }
public RouteHandlerBuilder? RegisterRoute { get; }
public RouteHandlerBuilder? AddCredentialRoute { get; }
public PasswordlessEndpointConventionBuilder(
RouteGroupBuilder groupBuilder,
RouteHandlerBuilder? loginRoute,
RouteHandlerBuilder? registerRoute,
RouteHandlerBuilder? addCredentialRoute)
{
_groupBuilder = groupBuilder;
LoginRoute = loginRoute;
RegisterRoute = registerRoute;
AddCredentialRoute = addCredentialRoute;
}
public void Add(Action<EndpointBuilder> convention)
{
((IEndpointConventionBuilder)_groupBuilder).Add(convention);
}
}