YGAuthentication 1.1.1
See the version list below for details.
dotnet add package YGAuthentication --version 1.1.1
NuGet\Install-Package YGAuthentication -Version 1.1.1
<PackageReference Include="YGAuthentication" Version="1.1.1" />
paket add YGAuthentication --version 1.1.1
#r "nuget: YGAuthentication, 1.1.1"
// Install YGAuthentication as a Cake Addin #addin nuget:?package=YGAuthentication&version=1.1.1 // Install YGAuthentication as a Cake Tool #tool nuget:?package=YGAuthentication&version=1.1.1
YGAuthentication
A working Authentication / Authorization functionality using JWT Claims. This version 1.0 will authenticate clear passwords to api/login Authentication with BCrypt one way encryption to api/loginEncr
Installation
Include this package in the project file
Be sure to follow the working POC example. The source code includes POC Web app.
Usage
.csproj file:
<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup>
<ItemGroup> <PackageReference Include="Blazored.LocalStorage" Version="4.5.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="YGAuthentication" Version="1.0.0" /> </ItemGroup>
AppSettings.json:
{
"AuthName": "YGAuthentication",
"LoginPage": "/Login"
}
program.cs:
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using YGAuthentication.ActionFilters;
using YGAuthentication.Auth;
using YGAuthentication.States;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
IConfiguration config = builder.Configuration;
string authName = config.GetValue<string>("AuthName");
string loginPage = config.GetValue<string>("LoginPage");
string username = "yogi";
string pwd = "123";
Dictionary<string, string> userCreds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
userCreds.Add(username, pwd); // Populate this with username and password from DB
Dictionary<string, string> userCredsHashed = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
userCredsHashed.Add(username, pwdEncrypted); // Populate this with username and password from DB. The password is BCrypt-hashed
int jwtExpMinutes = 60;
builder.Services.AddHttpClient(authName);
builder.Services.AddControllers();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddScoped<IAuthorizationJWT, AuthorizationJWT>(_ => new AuthorizationJWT(userCreds, "username", jwtExpMinutes, "Contoso", "General Audience"));
builder.Services.AddScoped<IAuthenticateEncrypted, AuthenticateEncrypted>(_ => new AuthenticateEncrypted(userCredsHashed, "username", jwtExpMinutes, "Contoso", "General Audience"));
builder.Services.AddScoped<IAppState, AppState>(_ => new AppState());
builder.Services.AddScoped<BasicAuthentication>();
builder.Services.AddScoped<IPageAuthCheck, PageAuthCheck>(ioc => new PageAuthCheck(ioc.GetService<NavigationManager>(), ioc.GetService<IHttpClientFactory>(), ioc.GetService<ILocalStorageService>(), authName, loginPage));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "mvc",
pattern: "{controller}/{action}/{id?}");
app.UseAntiforgery();
app.MapControllers();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
Login Page:
@page "/Login"
@rendermode InteractiveServer
@using Blazored.LocalStorage
@using YGAuthentication;
@using YGAuthentication.States
@inject NavigationManager _navmgr
@inject ILocalStorageService _localStorage
@inject IHttpClientFactory _iHttpClientFactory
@inject IAppState _appstate
@inject IConfiguration _config
<div class="clearfix">
<div class="floatLeft">Username</div>
<div class="floatLeft"><input type="text" @bind="Username" /></div>
</div>
<div class="clearfix">
<div class="floatLeft">Password</div>
<div class="floatLeft"><input type="password" @bind="Password" /></div>
</div>
<br />
<div class="clearfix">
<button class="btn btn-primary" @onclick="ButtonLogin">Login</button>
</div>
@if (Processing)
{
<div>
<img src="ajax-loader.gif" />
</div>
}
<div class="clearfix top20">
@Message
</div>
public partial class Login
{
public bool Processing { get; private set; }
public string Username { get; set; } = "";
public string Password { get; set; } = "";
public string Message { get; set; } = "";
protected override void OnInitialized()
{
base.OnInitialized();
Message = "Please log in";
this.StateHasChanged();
}
public async Task ButtonLogin()
{
try
{
Processing = true;
this.Message = "Please wait ..";
this.StateHasChanged();
string authName = _config.GetValue<string>("AuthName");
using (HttpClient httpclient = _iHttpClientFactory.CreateClient())
{
LoginDTO login = new LoginDTO() { Username = Username, Password = Password };
string jsonPayload = JsonConvert.SerializeObject(login);
HttpContent payload = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
//var result = await httpclient.PostAsync($"{_navmgr.BaseUri}api/login", payload); // When the passwords in IDS is clear text
var result = await httpclient.PostAsync($"{_navmgr.BaseUri}api/loginEncr", payload); // When the passwords in IDS is encrypted
if (result.StatusCode == System.Net.HttpStatusCode.OK)
{
string jwt = await result.Content.ReadAsStringAsync();
await _localStorage.SetItemAsStringAsync(authName, jwt);
_appstate.LoggedIn = true;
_navmgr.NavigateTo("/");
}
else
{
this.Message = result.StatusCode.ToString();
}
}
}
catch (Exception ex)
{
this.Message = ex.Message;
}
Processing = false;
this.StateHasChanged();
}
}
Any razor pages that needs authorization:
@page "/"
@rendermode InteractiveServer
@using YGAuthentication.Auth
@using YGAuthentication.States
@inject IPageAuthCheck _pageAuthCheck
@inject IAppState _appState
@code {
public string Message { get; private set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await _pageAuthCheck.AuthCheckAsync();
string isIsNot = _pageAuthCheck.EditAuthorized ? "is" : "is not";
Message = $"User {_pageAuthCheck.UserName} {isIsNot} authorized. Expiration: {_pageAuthCheck.AuthExp}";
_appState.LoggedIn = true;
StateHasChanged();
}
}
}
NavMenu:
@code {
private bool _isLoggedIn; // show restricted elements based on this flag
protected override void OnInitialized()
{
base.OnInitialized();
_isLoggedIn = _appState.LoggedIn;
_appState.OnChange += CheckUserLogin;
}
private void CheckUserLogin()
{
if (_isLoggedIn != _appState.LoggedIn)
{
_isLoggedIn = _appState.LoggedIn;
this.StateHasChanged();
}
}
private void SetLogout()
{
_isLoggedIn = false;
this.StateHasChanged();
}
public void Dispose()
{
_appState.OnChange -= CheckUserLogin;
}
}
Examples
A full working POC BlazorApp3 is provided in the Repo.
Output:
Blazor Web Application that uses log in
Dependencies
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.5.2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.2" />
Contributing
Any new ideas on how to enhance this class without adding much complexity, please adhere to SOLID principle
License
This project is licensed under the MIT License(LICENSE).
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- BCrypt.Net-Next (>= 4.0.3)
- Blazored.LocalStorage (>= 4.5.0)
- Microsoft.AspNetCore.Mvc.Abstractions (>= 2.2.0)
- Microsoft.AspNetCore.Mvc.Formatters.Json (>= 2.2.0)
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.IdentityModel.Tokens (>= 7.5.2)
- System.IdentityModel.Tokens.Jwt (>= 7.5.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Updated Readme.md