本文章以客户端基础,实现类似后台系统,进入后台控制台页面需要经过登录身份验证才可访问情况
简单来时就是实现前后端分离,前端通过 token和用户信息进行身份认证,或者在 AuthenticationStateProvider 实现方法 GetAuthenticationStateAsync 中调用后台接口进行身份验证
安装依赖Microsoft.AspNetCore.Components.Authorization、Blazored.LocalStorage
自定义AuthenticationStateProvider
using Blazored.LocalStorage; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Model.Entity; using System.Net.Http.Headers; using System.Security.Claims;namespace font.Authorization {public class HAuthenticationStateProvider : AuthenticationStateProvider { public HttpClient? _httpClient { set; get; }private AuthenticationService service;public HAuthenticationStateProvider(AuthenticationService service, HttpClient _httpClient){ this._httpClient = _httpClient; this.service = service;service.UserChanged += (newUser) =>{NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(newUser)));};service.LoginInState += MarkUserAsAuthenticated;service.LogoutState += MarkUserAsLoggedOut;}/// <summary>/// 身份认证提供/// </summary>/// <returns></returns>/// <exception cref="NotImplementedException"></exception>public override Task<AuthenticationState> GetAuthenticationStateAsync(){var savedToken = service.GetAccessToken();if (string.IsNullOrWhiteSpace(savedToken)){return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));}// 已认证过请求时带上token_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(service._bearer, savedToken);var user = service.GetUserDetail();if (user == null){var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());return Task.FromResult(new AuthenticationState(anonymousUser));}return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity( new[]{ new Claim(ClaimTypes.Name, user.UserName), new Claim("userId", user.UserId.ToString()) }, service._authentication))));}/// <summary>/// 辅助登录后刷新认证状态/// </summary>/// <param name="token"></param>public void MarkUserAsAuthenticated(string token, UserDetail user){var authenticatedUser = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, user.UserName), new Claim("userId", user.Id.ToString()) }, service._authentication))); var authState = Task.FromResult(authenticatedUser);NotifyAuthenticationStateChanged(authState);}/// <summary>/// 退出登录后刷新状态/// </summary>public void MarkUserAsLoggedOut(){var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());var authState = Task.FromResult(new AuthenticationState(anonymousUser));NotifyAuthenticationStateChanged(authState);}} }
自定义 AuthenticationService 管理登录和注销操作
using Blazored.LocalStorage; using Microsoft.AspNetCore.Components; using Model.Entity; using System.Security.Claims;namespace font.Authorization {public class AuthenticationService{public readonly string _token = "accessToken";public readonly string _bearer = "bearer";public readonly string _userDetail = "userDetail";public readonly string _authentication = "User Authentication";public event Action<ClaimsPrincipal>? UserChanged;public event Action<string, UserDetail>? LoginInState;public event Action? LogoutState;public readonly ISyncLocalStorageService localStorageService; private ClaimsPrincipal? currentUser;public ClaimsPrincipal CurrentUser{get { return currentUser ?? new(); }set{currentUser = value;if (UserChanged is not null){UserChanged(currentUser);}}}public AuthenticationService(ISyncLocalStorageService _syncLocalStorageService){this.localStorageService = _syncLocalStorageService;}public void LoginIn(string accessToken, UserDetail userDetail){SetAccessToken(accessToken);SetUserDetail(userDetail);LoginInState(accessToken, userDetail);}public void Logout(){RemoveAccessToken();RemoveUserDetail();LogoutState();}public ClaimsPrincipal GetUserClaimsPrincipal(UserDetail user){var identity = new ClaimsIdentity(new[]{new Claim(ClaimTypes.Name, user.UserName),new Claim("Id", user.Id.ToString()),new Claim("userId", user.UserId.ToString()),},_authentication);return new ClaimsPrincipal(identity);}public void RemoveAccessToken(){localStorageService.RemoveItem(_token);}public string? GetAccessToken(){return localStorageService.GetItemAsString(_token);}public void SetAccessToken(string accessToken){localStorageService.SetItemAsString(_token, accessToken);}public UserDetail? GetUserDetail(){return localStorageService.GetItem<UserDetail>(_userDetail);}public void RemoveUserDetail(){localStorageService.RemoveItem(_userDetail);}public void SetUserDetail(UserDetail userDetail){localStorageService.SetItem<UserDetail>(_userDetail, userDetail);}} }
Program.cs
builder.Services.AddOptions(); builder.Services.AddAuthorizationCore(); builder.Services.AddScoped<AuthenticationService>(); builder.Services.AddScoped<AuthenticationStateProvider, HAuthenticationStateProvider>();
在布局组件或者具体组件内使用
<CascadingAuthenticationState><AuthorizeView><Authorized><Layout><Sider class="main-container" @bind-Collapsed=@collapsed NoTrigger OnCollapse="OnCollapse"><div class="logo1" /><NavMenu collapsed="@collapsed" /></Sider><Layout class="site-layout"><Header class="site-layout-background" Style="padding: 0;">@if (collapsed){<Icon Type="menu-unfold" Theme="outline" class="trigger" OnClick="toggle" Style=" font-size: 30px;margin-left: 10px;" />}else{<Icon Type="menu-fold" Theme="outline" class="trigger" OnClick="toggle" Style=" font-size: 30px;margin-left: 10px;" />}</Header><Content class="site-layout-background content-container" Style="margin: 24px 16px;padding: 24px;min-height: 280px;">@Body</Content></Layout></Layout></Authorized><NotAuthorized><Login /></NotAuthorized></AuthorizeView> </CascadingAuthenticationState>
自定义登录组件和授权后的页面,注入 进行登录和注销测试
再刷新页面测试 和注销测试
已授权首页代码
@page "/" @inject IMessageService _message @inject AuthenticationService serivce<PageTitle>Home</PageTitle> <h1>Hello, world!</h1> Welcome to your new app.<Button Type="primary">Primary</Button> <Button Type="primary">Primary</Button> <br /> <Button Type="primary" OnClick="@OnClick">Display normal message </Button>@code{private void OnClick(){Console.WriteLine("onclick");_message.Info("退出登录成功!");serivce.Logout();} }
登录组件代码
@layout EmptyLayout @page "/login" @inject AuthenticationService au @inject IMessageService message<h3>Login</h3> <Button Type="@ButtonType.Primary" OnClick="@login" Size="30" Shape="@ButtonShape.Round" >登录</Button>@code {void login(){UserDetail userDetail = new UserDetail() { Id = 1, UserId = 12, UserName = "hygge" };au.CurrentUser = au.GetUserClaimsPrincipal(userDetail);au.LoginIn("jwerqwert", userDetail);message.Success("登录成功!");} }
简单的登录认证就完成了
用户详情代码
public class UserDetail{public int Id { get; set; }public int UserId { get; set; }public string UserName { get; set; }}