1414<MudText Typo =" Typo.h3" GutterBottom =" true" >Log in</MudText >
1515
1616<MudGrid >
17- <MudItem md =" 6" >
18- <StatusMessage Message =" @_errorMessage" />
19- <EditForm EditContext =" _editContext" method =" post" OnSubmit =" LoginUser" FormName =" login" >
20- <DataAnnotationsValidator />
21-
22- <MudText GutterBottom =" true" Typo =" Typo.body1" Color =" Color.Primary" >
23- Use a local account to log in.
24- </MudText >
25-
26- <MudGrid >
27- <MudItem xs =" 12" >
28- <MudStaticTextField For =" @(() => Input.Email)" @bind-Value =" Input.Email" Label =" Email"
29- Placeholder =" name@example.com"
30- UserAttributes =" @(new Dictionary<string, object?> { { " autocomplete " , " username webauthn " }, { " aria-required " , " true " } })" />
31- </MudItem >
32- <MudItem xs =" 12" >
33- <MudStaticTextField For =" @(() => Input.Password)" @bind-Value =" Input.Password" Label =" Password"
34- InputType =" InputType.Password" Placeholder =" password"
35- UserAttributes =" @(new Dictionary<string, object?> { { " autocomplete " , " current-password " }, { " aria-required " , " true " } })" />
36- </MudItem >
37- <MudItem xs =" 12" >
38- <MudStaticCheckBox For =" @(() => Input.RememberMe)" @bind-Value =" Input.RememberMe" >Remember me
39- </MudStaticCheckBox >
40- </MudItem >
41- <MudItem xs =" 12" Class =" d-flex gap-4" >
42- <MudStaticButton Variant =" Variant.Outlined" Color =" Color.Primary" FormAction =" FormAction.Submit" >Log
43- in</MudStaticButton >
44- <PasskeySubmit Operation =" PasskeyOperation.Request" Name =" Input.Passkey" EmailName =" Input.Email"
45- Variant =" Variant.Outlined" Color =" Color.Secondary" >
46- Sign in with a passkey
47- </PasskeySubmit >
48- </MudItem >
49- </MudGrid >
50- </EditForm >
51-
52- @if (! string .IsNullOrEmpty (Input .Passkey ? .Error ))
17+ <MudItem md =" 6" >
18+ <StatusMessage Message =" @_errorMessage" />
19+ <EditForm EditContext =" _editContext" method =" post" OnSubmit =" LoginUser" FormName =" login" >
20+ <DataAnnotationsValidator />
21+
22+ <MudText GutterBottom =" true" Typo =" Typo.body1" Color =" Color.Primary" >
23+ Use a local account to log in.
24+ </MudText >
25+
26+ <MudGrid >
27+ <MudItem xs =" 12" >
28+ <MudStaticTextField For =" @(() => Input.Email)" @bind-Value =" Input.Email" Label =" Email"
29+ Placeholder =" name@example.com"
30+ UserAttributes =" @(new Dictionary<string, object?> { { " autocomplete " , " username webauthn " }, { " aria-required " , " true " } })" />
31+ </MudItem >
32+ <MudItem xs =" 12" >
33+ <MudStaticTextField For =" @(() => Input.Password)" @bind-Value =" Input.Password" Label =" Password"
34+ InputType =" InputType.Password" Placeholder =" password"
35+ UserAttributes =" @(new Dictionary<string, object?> { { " autocomplete " , " current-password " }, { " aria-required " , " true " } })" />
36+ </MudItem >
37+ <MudItem xs =" 12" >
38+ <MudStaticCheckBox For =" @(() => Input.RememberMe)" @bind-Value =" Input.RememberMe" >Remember me
39+ </MudStaticCheckBox >
40+ </MudItem >
41+ <MudItem xs =" 12" Class =" d-flex gap-4" >
42+ <MudStaticButton Variant =" Variant.Outlined" Color =" Color.Primary" FormAction =" FormAction.Submit" >Log
43+ in</MudStaticButton >
44+ <PasskeySubmit Operation =" PasskeyOperation.Request" Name =" Input.Passkey" EmailName =" Input.Email"
45+ Variant =" Variant.Outlined" Color =" Color.Secondary" >
46+ Sign in with a passkey
47+ </PasskeySubmit >
48+ </MudItem >
49+ </MudGrid >
50+ </EditForm >
51+
52+ @if (! string .IsNullOrEmpty (Input .Passkey ? .Error ))
53+ {
54+ <MudAlert Severity =" Severity.Error" Variant =" Variant.Text" Class =" mt-4" >
55+ @Input.Passkey.Error
56+ </MudAlert >
57+ }
58+
59+ <MudGrid Class =" mt-4" >
60+ <MudItem xs =" 12" >
61+ <MudLink Href =" Account/ForgotPassword" >Forgot your password?</MudLink ><br />
62+ @if (_isPublicRegistrationEnabled )
5363 {
54- <MudAlert Severity =" Severity.Error" Variant =" Variant.Text" Class =" mt-4" >
55- @Input.Passkey.Error
56- </MudAlert >
57- }
64+ <MudLink
65+ Href =" @(NavigationManager.GetUriWithQueryParameters(" Account /Register " , new Dictionary<string, object?> { [" ReturnUrl " ] = ReturnUrl }))" >
66+ Register as a new user </MudLink >
5867
59- <MudGrid Class =" mt-4" >
60- <MudItem xs =" 12" >
61- <MudLink Href =" Account/ForgotPassword" >Forgot your password?</MudLink ><br />
62- @if (_isPublicRegistrationEnabled )
63- {
64- <MudLink
65- Href =" @(NavigationManager.GetUriWithQueryParameters(" Account /Register " , new Dictionary<string, object?> { [" ReturnUrl " ] = ReturnUrl }))" >
66- Register as a new user </MudLink >
67-
68- <br />
69- }
70- <MudLink Href =" Account/ResendEmailConfirmation" >Resend email confirmation</MudLink >
71- </MudItem >
72- </MudGrid >
73- </MudItem >
74- <MudItem md =" 6" >
75- <MudText Typo =" Typo.body1" Color =" Color.Secondary" GutterBottom =" true" >
76- Log in with an external provider.
77- </MudText >
78- <ExternalLoginPicker />
79- </MudItem >
68+ <br />
69+ }
70+ <MudLink Href =" Account/ResendEmailConfirmation" >Resend email confirmation</MudLink >
71+ </MudItem >
72+ </MudGrid >
73+ </MudItem >
74+ <MudItem md =" 6" >
75+ <MudText Typo =" Typo.body1" Color =" Color.Secondary" GutterBottom =" true" >
76+ Log in with an external provider.
77+ </MudText >
78+ <ExternalLoginPicker />
79+ </MudItem >
8080</MudGrid >
8181
8282@code {
83- private string ? _errorMessage ;
84- private bool _isPublicRegistrationEnabled ;
85- private EditContext _editContext = default ! ;
83+ private string ? _errorMessage ;
84+ private bool _isPublicRegistrationEnabled ;
85+ private EditContext _editContext = default ! ;
8686
87- [CascadingParameter ]
88- private HttpContext HttpContext { get ; set ; } = default ! ;
87+ [CascadingParameter ]
88+ private HttpContext HttpContext { get ; set ; } = default ! ;
8989
90- [SupplyParameterFromForm ]
91- private InputModel Input { get ; set ; } = default ! ;
90+ [SupplyParameterFromForm ]
91+ private InputModel Input { get ; set ; } = default ! ;
9292
93- [SupplyParameterFromQuery ]
94- private string ? ReturnUrl { get ; set ; }
93+ [SupplyParameterFromQuery ]
94+ private string ? ReturnUrl { get ; set ; }
9595
96- protected override async Task OnInitializedAsync ()
97- {
98- Input ??= new InputModel ();
99- _editContext = new EditContext (Input );
96+ protected override async Task OnInitializedAsync ()
97+ {
98+ Input ??= new InputModel ();
99+ _editContext = new EditContext (Input );
100100
101- if (HttpMethods .IsGet (HttpContext .Request .Method ))
102- {
103- // Clear the existing external cookie to ensure a clean login process
104- await HttpContext .SignOutAsync (IdentityConstants .ExternalScheme );
105- }
106-
107- var settingsResult = await ServerSettingsApi .GetPublicRegistrationSettings ();
108- if (settingsResult .IsSuccess )
109- {
110- _isPublicRegistrationEnabled = settingsResult .Value .IsPublicRegistrationEnabled ;
111- }
101+ if (HttpMethods .IsGet (HttpContext .Request .Method ))
102+ {
103+ // Clear the existing external cookie to ensure a clean login process
104+ await HttpContext .SignOutAsync (IdentityConstants .ExternalScheme );
112105 }
113106
114- public async Task LoginUser ()
107+ var settingsResult = await ServerSettingsApi .GetPublicRegistrationSettings ();
108+ if (settingsResult .IsSuccess )
115109 {
116- if (! string .IsNullOrEmpty (Input .Passkey ? .Error ))
117- {
118- _errorMessage = $" Error: {Input .Passkey .Error }" ;
119- return ;
120- }
110+ _isPublicRegistrationEnabled = settingsResult .Value .IsPublicRegistrationEnabled ;
111+ }
112+ }
121113
122- SignInResult result ;
114+ public async Task LoginUser ()
115+ {
116+ if (! string .IsNullOrEmpty (Input .Passkey ? .Error ))
117+ {
118+ _errorMessage = $" Error: {Input .Passkey .Error }" ;
119+ return ;
120+ }
123121
124- if (! string .IsNullOrEmpty (Input .Passkey ? .CredentialJson ))
125- {
126- result = await PasskeySignInManager .PasskeySignInAsync (Input .Passkey .CredentialJson );
127- }
128- else
129- {
130- if (! _editContext .Validate ())
131- {
132- return ;
133- }
122+ SignInResult result ;
123+ var passKeyCred = $" {Input .Passkey ? .CredentialJson }" ;
124+ var isPassKeyLogin = ! string .IsNullOrWhiteSpace (passKeyCred );
134125
135- result = await SignInManager .PasswordSignInAsync (Input .Email , Input .Password , Input .RememberMe , true );
136- }
126+ if (isPassKeyLogin )
127+ {
128+ result = await PasskeySignInManager .PasskeySignInAsync (passKeyCred );
129+ }
130+ else
131+ {
132+ if (! _editContext .Validate ())
133+ {
134+ return ;
135+ }
137136
138- if (result .Succeeded )
139- {
140- Logger .LogInformation (" User '{Email}' logged in." , Input .Email );
141- RedirectManager .RedirectTo (ReturnUrl );
142- }
143- else if (result .RequiresTwoFactor )
144- {
145- RedirectManager .RedirectTo (
146- " Account/LoginWith2fa" ,
147- new Dictionary <string , object ?> { [" returnUrl" ] = ReturnUrl , [" rememberMe" ] = Input .RememberMe });
148- }
149- else if (result .IsLockedOut )
150- {
151- Logger .LogCritical (" User account locked out. Account: {Email}" , Input .Email );
152- RedirectManager .RedirectTo (" Account/Lockout" );
153- }
154- else
155- {
156- _errorMessage = " Error: Invalid login attempt." ;
157- }
137+ result = await SignInManager .PasswordSignInAsync (Input .Email , Input .Password , Input .RememberMe , true );
158138 }
159139
160- private sealed class InputModel
140+ if (result .Succeeded )
141+ {
142+ if (isPassKeyLogin )
143+ {
144+ Logger .LogInformation (" User logged in via passkey." );
145+ }
146+ else
147+ {
148+ Logger .LogInformation (" User '{Email}' logged in with a password." , Input .Email );
149+ }
150+
151+ RedirectManager .RedirectTo (ReturnUrl );
152+ }
153+ else if (result .RequiresTwoFactor )
154+ {
155+ RedirectManager .RedirectTo (
156+ " Account/LoginWith2fa" ,
157+ new Dictionary <string , object ?> { [" returnUrl" ] = ReturnUrl , [" rememberMe" ] = Input .RememberMe });
158+ }
159+ else if (result .IsLockedOut )
161160 {
162- [Required ]
163- [EmailAddress ]
164- public string Email { get ; set ; } = " " ;
161+ if (isPassKeyLogin )
162+ {
163+ Logger .LogCritical (" User account locked out via passkey login." );
164+ }
165+ else
166+ {
167+ Logger .LogCritical (" User account locked out. Account: {Email}" , Input .Email );
168+ }
169+ RedirectManager .RedirectTo (" Account/Lockout" );
170+ }
171+ else
172+ {
173+ _errorMessage = " Error: Invalid login attempt." ;
174+ }
175+ }
165176
166- [Required ]
167- [DataType (DataType .Password )]
168- public string Password { get ; set ; } = " " ;
177+ private sealed class InputModel
178+ {
179+ [Required ]
180+ [EmailAddress ]
181+ public string Email { get ; set ; } = " " ;
169182
170- [Display (Name = " Remember me?" )]
171- public bool RememberMe { get ; set ; }
183+ [Required ]
184+ [DataType (DataType .Password )]
185+ public string Password { get ; set ; } = " " ;
172186
173- public PasskeyInputModel ? Passkey { get ; set ; }
174- }
187+ [Display (Name = " Remember me?" )]
188+ public bool RememberMe { get ; set ; }
189+
190+ public PasskeyInputModel ? Passkey { get ; set ; }
191+ }
175192
176193}
0 commit comments