Blazor WebAssembly, Part 3: Authentication and Authorization

Source: Heise.de added 30th Dec 2020

  • blazor-webassembly,-part-3:-authentication-and-authorization

Already when creating a Blazor WebAssembly project in Visual Studio or on the command line with dotnet new there are options to configure an authentication. With the option ASP.NET Core Hosted in connection with Individual Accounts | Store user accounts in-app you get a mixture of a Blazor WebAssembly application with a user login and administration implemented in ASP.NET Core Razor (as a server-side solution). Alternatively, you can connect to an OIDC provider (Open ID Connect).

The third of the tutorial shows how you can use any WebAPI backend for authentication, even if it is not OIDC compatible. The MiracleList backend implements its own authentication mechanism based on user names and passwords for logging in, which then provides an authentication token (as a character string) for subsequent WebAPI calls. In the first part of the tutorial, the AuthenticationManager class was implemented, which enables this mechanism in the Login () encapsulates. So far it was called in the component Index.razor . This should now be shifted to a separate login page.

Login page for the front end Figure 1 visualizes the login page to be created in the MiracleList Blazor front end with input for user name and Password and a button. Listing 1 shows the associated Razor template page Login.razor and Listing 2 the matching code-behind file.

Login page generated from the Razor component “Login.razor” (Fig. 1)

using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using System.Threading.Tasks; namespace Web {public class LoginModel: ComponentBase { public NavigationManager NavigationManager {get; set; } AuthenticationStateProvider asp {get; set; } = zero; #region properties for data binding public string Username {get; set; } public string Password {get; set; } public string Message {get; set; } #endregion protected override async System.Threading.Tasks.Task OnInitializedAsync () {// response to this URL if (this.NavigationManager.Uri.ToLower (). Contains (“https://www.heise.de/logout” )) {await ((AuthenticationManager) asp) .Logout (); }} /// /// Reaction to user action /// protected async Task Login () {Message = “Logging in …”; bool ok = await (asp as AuthenticationManager) .Login (Username, Password); if (ok) this.NavigationManager.NavigateTo (“https://www.heise.de/main”); else Message = “Login Error!”; }} // end class Login} Listing 1: Razor template for the login page (Login.razor)

@ page “/” @page “https://www.heise.de / Logout “@inherits LoginModel; User login MiracleList is a sample application for a single-page web application (SPA) with ASP.NET Core Blazor Webassembly (@ System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription) for task management. Author: Dr. Holger Schwichtenberg, www.IT-Visions.de, 2018 – @ DateTime.Now.Year
Enter the combination of your e-mail address for user login and any password. If there is not yet a user account for this e-mail address, a new user account is automatically created with a few sample tasks.
E-mail address: Password Register @ ErrorMsg MiracleList Tutorial v @ System.Reflection .Assembly.GetExecutingAssembly (). GetName (). Version.ToString () Listing 2: Code-behind file for the login page (Login.razor.cs)

In the program code, readers will see for the first time in this tutorial how to redirect from one URL to another. To do this, you can create an instance of the Blazor class NavigationManager

public NavigationManager NavigationManager {get; set; } inject and then use the method NavigateTo () specifying the relative destination URL:

this.NavigationManager.NavigateTo (“https://www.heise.de/abc/def”); You can also use the NavigationManager to check the current Query URL. Listing 1 shows two different routes with @ page for the Razor Component Login.razor Directives defined. That is permitted in Blazor; it is up to software developers to give this meaning. In the program code in the life cycle event OnInitializedAsync () (Listing 2), a distinction is made between the fact that when the call is made with the relative address / logout a deregistration takes place and then the registration form appears again. This is an elegant solution that allows you to call up the URL http: // server / logout can execute the registration.

So that the revised program code of the code-behind file Login.razor.cs recompiled, is in AuthenticationManager a routine Logout () to supplement the operation / Logoff calls in the server (see Listing 3).

using System.Threading.Tasks; using system; using System.Security.Claims; // NEW in Part 3 using Microsoft.AspNetCore.Components.Authorization; // NEW in Part 3 using MiracleListAPI; namespace Web {/// /// Authentication for debugging /// public class AuthenticationManager: AuthenticationStateProvider // Inheritance NEW in part 3 {MiracleListAPI.MiracleListProxy proxy {get; set; } public AuthenticationManager (MiracleListAPI.MiracleListProxy proxy) {this.proxy = proxy; } public const string ClientID = “2018 – 1111 – 1111 – 1111 – 111111111111 “; public LoginInfo CurrentLoginInfo = null; public string Token {get {return CurrentLoginInfo? .Token; }} /// /// Login to be called by Razor Component Login.razor /// public async task Login (string username, string password) {bool result = false; CurrentLoginInfo = null; var l = new LoginInfo () {Username = username, Password = password, ClientID = AuthenticationManager.ClientID}; try {CurrentLoginInfo = await proxy.LoginAsync (l); if (String.IsNullOrEmpty (CurrentLoginInfo.Token)) {Console.WriteLine (“Login NOT successful:” + this.CurrentLoginInfo.Username); } else {result = true; Console.WriteLine (“Login successful:” + this.CurrentLoginInfo.Username); }} catch (Exception ex) {Console.WriteLine (“Login error:” + ex.Message); } Notify (); return result; } /// /// Logout to be called by Razor Component Login.razor /// public async Task Logout () {Console.WriteLine (“Logout”, this.CurrentLoginInfo); if (this.CurrentLoginInfo == null) return; var e = await proxy.LogoffAsync (this.CurrentLoginInfo.Token); if (e) {// Remove LoginInfo in RAM for clearing authenticaton state CurrentLoginInfo = null; Notify (); } else {Console.WriteLine (“Logout Error!”); }} /// /// NEW in part 3: Notify Blazor infrastructure about new Authentication State // / private void Notify () {Console.WriteLine (“Notify:” + CurrentLoginInfo? .Username) ; this.NotifyAuthenticationStateChanged (GetAuthenticationStateAsync ()); } // NEW in part 3 public override async task 111111111111 GetAuthenticationStateAsync () {if (this.CurrentLoginInfo! = Null &&! String.IsNullOrEmpty (this.CurrentLoginInfo.Token) &&! String.IsNullOrEmpty (proxy.BaseUrl)) {const string authType = “MiracleList WebAPI Authentication”; var identity = new ClaimsIdentity (new [] {new Claim (“Backend”, proxy.BaseUrl), new Claim (ClaimTypes.Sid, this.CurrentLoginInfo.Token), // use SID claim for token new Claim (ClaimTypes. Name, this.CurrentLoginInfo.Username),}, authType); var cp = new ClaimsPrincipal (identity); var state = new AuthenticationState (cp); Console.WriteLine (“GetAuthenticationStateAsync:” + this.CurrentLoginInfo.Username); return state; } else {Console.WriteLine (“GetAuthenticationStateAsync: no user”); var state = new AuthenticationState (new ClaimsPrincipal (new ClaimsIdentity ())); return state; }}}} Listing 3: Extended class AuthenticationManager

In addition, the Login () method to be redesigned: Instead of using the static login data, this now requires two parameters for user name and password that can be set by the caller:

public async task Login (string username, string password) { var l = new LoginInfo () {Username = username, Password = password, ClientID = AuthenticationManager.ClientID}; …} Calling Login () in Index.razor.cs must be completely omitted. Off

protected override async Task OnInitializedAsync () {// TODO: Must be done later in the login screen if (await am.Login ()) {await ShowCategorySet (); }} becomes

protected override async Task OnInitializedAsync () {await ShowCategorySet (); } With this the application compiles again, but at the start it immediately runs into a runtime error: The error message “System.InvalidOperationException: The following routes are ambiguous: ‘/’ in ‘Web.Pages.Login’ ‘/’ in ‘Web.Pages.Index'” is meaningful: Each route can only be assigned to exactly one component. However, two root components have been defined for starting the application. It is therefore important to set the route in the file Index.razor change from

@ page “/” in

@ page “https://www.heise.de/main” Now developers are directed to the registration form when the application is started and after successful registration via NavigationManager with this .NavigationManager.NavigateTo (“https://www.heise.de/main”) to the main component index. razor . But unfortunately nothing prevents the user from being directly http: // server / main call and bypass the login.

Read the full article at Heise.de

brands: AM  CODE  Microsoft  New  
media: Heise.de  
keywords: App  Console  Server  Software  

Related posts


Notice: Undefined variable: all_related in /var/www/vhosts/rondea.com/httpdocs/wp-content/themes/rondea-2-0/single-article.php on line 88

Notice: Undefined variable: all_related in /var/www/vhosts/rondea.com/httpdocs/wp-content/themes/rondea-2-0/single-article.php on line 88

Related Products



Notice: Undefined variable: all_related in /var/www/vhosts/rondea.com/httpdocs/wp-content/themes/rondea-2-0/single-article.php on line 91

Warning: Invalid argument supplied for foreach() in /var/www/vhosts/rondea.com/httpdocs/wp-content/themes/rondea-2-0/single-article.php on line 91