主要参考学习张善友大神的提示,使用Blazored.LocalStorage包本地cookie方式
本文将以Server Side的方式介绍,WASM方式仅需修改少数代码即可完成移植,不再赘述。下文介绍的是基于Token的内网用户名/密码认证,出于登录演示机制的考虑,并不保证代码在安全逻辑层面是可靠的。不要使用未加改造的本文代码,使用在生产网络中!
Nuget安装Blazored.LocalStorage包。此包使用JS与客户端环境交互,保存/读取本地数据。
1 //ConfigureServices 2 services.AddAuthentication(); 3 services.AddAuthorization(); 4 services.AddControllers(); 5 services.AddHttpClient(); 6 services.AddBlazoredLocalStorage(); 7 //Configure 8 app.UseAuthentication(); 9 app.UseAuthorization(); 10 app.UseEndpoints(endpoints => { 11 //... 12 endpoints.MapControllers(); 13 //... 14 })
1 using Blazored.LocalStorage; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Threading.Tasks; 6 7 namespace BlazorAuthoriation.Data 8 { 9 public class CurrentUser 10 { 11 static string LOCAL_STORAGE_KEY = "stweily"; 12 public static async Task<CurrentUser> Load(ILocalStorageService localStorage) 13 { 14 var s = await localStorage.GetItemAsync<string>(LOCAL_STORAGE_KEY); 15 return FromStorageString(s); 16 } 17 public static CurrentUser FromStorageString(string s) 18 { 19 if (s == null) 20 return null; 21 return new CurrentUser() { UserName= s }; 22 //return null; 23 } 24 public static async Task Remove(Blazored.LocalStorage.ILocalStorageService localStorage) 25 { 26 await localStorage.RemoveItemAsync(LOCAL_STORAGE_KEY); 27 } 28 public static async Task Login(Blazored.LocalStorage.ILocalStorageService localStorage,string name, string pwd) 29 { 30 await localStorage.SetItemAsync<string>(LOCAL_STORAGE_KEY, name); 31 } 32 public string UserName { set; get; } 33 } 34 }
1 @page "/login" 2 @using BlazorAuthoriation.Data 3 @inject NavigationManager nav 4 @*@inject Blazored.SessionStorage.ISessionStorageService storage*@ 5 @inject Blazored.LocalStorage.ILocalStorageService storage 6 7 @if (null == currUser) 8 { 9 <h3> 10 账号:<input /> 11 密码:<input /> 12 <button @onclick="login">确定</button> 13 </h3> 14 } 15 else 16 { 17 <h3> 18 Welcome,<b> @currUser.UserName </b>! 19 <button @onclick="logout">退出</button> 20 </h3> 21 } 22 @code { 23 [CascadingParameter] 24 protected CurrentUser currUser { get; set; } 25 26 [Parameter] 27 public EventCallback<string> LoginEvents { get; set; } 28 [Parameter] 29 public EventCallback LogoutEvents { get; set; } 30 private async Task RaiseLoginEvent() 31 { 32 if (LoginEvents.HasDelegate) 33 { 34 await LoginEvents.InvokeAsync(null); 35 StateHasChanged(); 36 } 37 } 38 private async Task RaiseLogoutEvent() 39 { 40 if (LogoutEvents.HasDelegate) 41 { 42 await LogoutEvents.InvokeAsync(null); 43 StateHasChanged(); 44 } 45 } 46 47 private async Task logout() 48 { 49 await CurrentUser.Remove(storage); 50 await RaiseLogoutEvent(); 51 nav.NavigateTo("/"); 52 } 53 private async void login() 54 { 55 await CurrentUser.Login(storage, "stweily", "123"); 56 await RaiseLoginEvent(); 57 nav.NavigateTo("/"); 58 } 59 }
1 @inherits LayoutComponentBase 2 @inject NavigationManager nav 3 @inject Blazored.LocalStorage.ILocalStorageService storage 4 @using BlazorAuthoriation.Data 5 @using BlazorAuthoriation.Pages 6 7 <div class="sidebar"> 8 <NavMenu /> 9 </div> 10 <CascadingValue Value="currUser"> 11 <div class="main"> 12 <div class="top-row px-4"> 13 @*<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>*@ 14 <Login LoginEvents="(e)=>LoginEvent(e)" LogoutEvents="(e)=>LogoutEvent(e)" /> 15 </div> 16 <div class="content px-4"> 17 @if (currUser == null) 18 { 19 <h3>请登录以后再操作内容!!</h3> 20 } 21 else 22 @Body 23 </div> 24 </div> 25 </CascadingValue> 26 @code{ 27 /// <summary> 28 /// 强制刷新标志 29 /// </summary> 30 private bool forceRender { get; set; } = false; 31 private void LogoutEvent(object username) 32 { 33 //msg.Info($"See you later {(string)username}"); 34 //通过 LoginControl 组件回调 接收强制刷新消息 35 //loginControl.ChildEvents.InvokeAsync("this is key"); 36 //currUser = null; 37 forceRender = true; 38 } 39 private void LoginEvent(object username) 40 { 41 //msg.Info($"See you later {(string)username}"); 42 //通过 LoginControl 组件回调 接收强制刷新消息 43 //loginControl.ChildEvents.InvokeAsync("this is key"); 44 //currUser = null; 45 forceRender = true; 46 } 47 48 protected override async Task OnAfterRenderAsync(bool firstRender) 49 { 50 base.OnAfterRender(firstRender); 51 if (firstRender || forceRender) 52 { 53 forceRender = false; 54 55 currUser = await CurrentUser.Load(storage); 56 if (null == currUser) 57 nav.NavigateTo("/Login"); 58 else 59 StateHasChanged(); 60 } 61 } 62 /// <summary> 63 /// 有 CascadingValue 加持, 所有子组件可以通过 [CascadingParameter] 继承读取 64 /// </summary> 65 private CurrentUser currUser { get; set; } 66 }