When creating a Blazer WebSite project in Visual Studio or on the command line dotnet new
There are options to configure authentication. With will Hosted by ASP.NET Core Affiliated with Personal Accounts | Save user accounts in the app You get the combination of the Blazer WebAuse app with user login and administration enabled on ASP.NET Core Racer (server side solution). Alternatively, you can connect with the OIDC provider (open ID link).
The third of the tutorial shows you how to use any WebAPI backend for authentication, even if it is not OIDC compliant. The Miraclelist-Backend Realizes its own authentication mechanism based on the username and password used to sign in, and then assigns an authentication token (character string) to subsequent WebAPI calls. In the first part of the tutorial, class AuthenticationManager
The system implements this mechanism Login()
Connecting. So far she has been in those elements Index.razor
Called. It is now to be moved to a separate login page.
Login page for front page
Figure 1 shows the login page to be created on the front-end of the Miraclelist blazer. Table 1 shows the corresponding razor template page Login.razor And 2 lists the appropriate code-back file.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.Threading.Tasks;
namespace Web
{
public class LoginModel : ComponentBase
{
[Inject] public NavigationManager NavigationManager { get; set; }
[Inject] AuthenticationStateProvider asp { get; set; } = null;
#region Properties für Datenbinding
public string Username { get; set; }
public string Password { get; set; }
public string Message { get; set; }
#endregion
protected override async System.Threading.Tasks.Task OnInitializedAsync()
{
// Reaktion auf diese URL
if (this.NavigationManager.Uri.ToLower().Contains("/logout"))
{
await ((AuthenticationManager)asp).Logout();
}
}
/// <summary>
/// Reaktion auf Benutzeraktion
/// </summary>
protected async Task Login()
{
Message = "Logging in...";
bool ok = await (asp as AuthenticationManager).Login(Username, Password);
if (ok) this.NavigationManager.NavigateTo("/main");
else Message = "Login Error!";
}
} // end class Login
}
List 1: Razor Template for Login Page (Login.razor)
@page "/"
@page "/Logout"
@inherits LoginModel;
<div class="panel panel-primary">
<div class="panel-heading">
<h2>Benutzeranmeldung</h2>
</div>
<div class="panel-body">
<div>MiracleList ist eine Beispielanwendung für eine Single-Page-Webapplication (SPA) mit ASP.NET Core Blazor Webassembly (@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription) zur Aufgabenverwaltung.</div>
<div>Autor: Dr. Holger Schwichtenberg, <a href="http://www.IT-Visions.de">www.IT-Visions.de</a>, [email protected]</div>
<br />
<div>
Zur Benutzeranmeldung geben Sie die Kombination aus Ihrer E-Mail-Adresse und einem beliebigen Kennwort ein. Wenn es für diese E-Mail-Adresse noch kein Benutzerkonto gibt, wird automatisch ein neues Benutzerkonto angelegt mit einigen Beispielaufgaben.
</div>
<br>
<div class="row">
<div class="col-xs-12 form-group">
<label for="name">E-Mail-Adresse:</label>
<input name="name" @bind="this.Username" id="name" type="text" placeholder="Ihre E-Mail-Adresse" class="form-control">
</div>
</div>
<div class="row">
<div class="col-xs-12 form-group">
<label for="password">Kennwort</label>
<input name="password" @bind="this.Password" id="password" placeholder="Ihr Kennwort" type="password" class="form-control">
</div>
</div>
<button @onclick="Login" class="btn btn-primary" type="submit" id="Anmelden" name="Anmelden">Anmelden</button>
<span id="errorMsg" class="text-danger">@ErrorMsg</span>
</div>
</div>
<text>MiracleList Tutorial v</text>@System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()
List 2: Code-back file for the login page (Login.razor.cs)
In the program code, readers of this tutorial will see for the first time how to redirect from one URL to another. To do this, you may have a pre-defined example in the blazer NavigationManager
[Inject] public NavigationManager NavigationManager { get; set; }
Use the method after injection NavigateTo()
Specifies the associated destination URL:
this.NavigationManager.NavigateTo("/abc/def");
You can use NavigationManager
Also query the current URL. Table 1 for razor equipment Login.razor
Two different ways directly @page
-Procedures are defined. In Blazer it is allowed; It is up to the software developers to provide this meaning. In the program code in the life cycle event OnInitializedAsync()
(List 2) So there is a difference between the call with the relative address /logout
A registration takes place, and then the registration form reappears. This is an elegant solution that allows you to call URLs from anywhere http: // server / logout Can register.
Hence the modified program code of the code-after file Login.razor.cs Re-compiled, is AuthenticationManager
A routine Logout()
To complete the surgery /Logoff
Calls on the server (see List 3).
using System.Threading.Tasks;
using System;
using System.Security.Claims; // NEU in Teil 3
using Microsoft.AspNetCore.Components.Authorization; // NEU in Teil 3
using MiracleListAPI;
namespace Web
{
/// <summary>
/// Authentifizierung zum Debugging
/// </summary>
public class AuthenticationManager : AuthenticationStateProvider // Vererbung NEU in Teil 3
{
MiracleListAPI.MiracleListProxy proxy { get; set; }
public AuthenticationManager(MiracleListAPI.MiracleListProxy proxy)
{
this.proxy = proxy;
}
public const string ClientID = "11111111-1111-1111-1111-111111111111";
public LoginInfo CurrentLoginInfo = null;
public string Token { get { return CurrentLoginInfo?.Token; } }
/// <summary>
/// Login to be called by Razor Component Login.razor
/// </summary>
public async Task<bool> 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("Anmeldung NICHT erfolgreich: " + this.CurrentLoginInfo.Username);
}
else
{
result = true;
Console.WriteLine("Anmeldung erfolgreich: " + this.CurrentLoginInfo.Username);
}
}
catch (Exception ex)
{
Console.WriteLine("Anmeldefehler: " + ex.Message);
}
Notify();
return result;
}
/// <summary>
/// Logout to be called by Razor Component Login.razor
/// </summary>
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!");
}
}
/// <summary>
/// NEU in Teil 3: Notify Blazor infrastructure about new Authentication State
/// </summary>
private void Notify()
{
Console.WriteLine("Notify: " + CurrentLoginInfo?.Username);
this.NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
// NEU in Teil 3
public override async Task<AuthenticationState> 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;
}
}
}
}
List 3: Extended Class Authorization Manager
In addition, the Login()
Method of redesigning: Instead of using standard login data, it now requires two parameters for username and password, which can be set by the caller:
public async Task<bool> Login(string username, string password)
{
var l = new LoginInfo() { Username = username, Password = password, ClientID = AuthenticationManager.ClientID };
...
}
Call Login()
In Index.razor.cs Should be avoided altogether. Out
protected override async Task OnInitializedAsync()
{
// TODO: Muss später im Anmeldebildschirm erfolgen
if (await am.Login())
{
await ShowCategorySet();
}
}
Therefore
protected override async Task OnInitializedAsync()
{
await ShowCategorySet();
}
The application compiles again, but runs in runtime error immediately when it starts: error message “System.InvalidOperationException: The following paths are unclear: ‘Web.Pages.Login’ ‘/’ ‘Web.Pages.Index’ in ‘/’ Makes sense: each path can only be assigned to exactly one component. However, two root components are defined to start the application. So it applies to the file Index.razor Change path from
@page "/"
In
@page "/main"
Developers are now sent to the registration form once the application has started and successfully registered through the navigation manager this.NavigationManager.NavigateTo("/main")
To the main component Index.razor. But unfortunately that did not stop users from using it later http: // server / main Avoid signing in.
“Avid writer. Subtly charming alcohol fanatic. Total twitter junkie. Coffee enthusiast. Proud gamer. Web aficionado. Music advocate. Zombie lover. Reader.”
More Stories
Acrylic Nails for the Modern Professional: Balancing Style and Practicality
The Majestic Journey of the African Spurred Tortoise: A Guide to Care and Habitat
Choosing Between a Russian and a Greek Tortoise: What You Need to Know