簡單粗暴的實現 Blazor Server 登錄鑑權

既然是簡單粗暴,那麼就不用關心諸如 IDentityServer4,OAuth 之類的組件,也不使用 AuthenticationStateProvider、IAuthService, razor 頁面上不用折騰 CascadingAuthenticationState 或者 AuthorizeView,單純用 Blazored.LocalStorage 搞事情就足夠了。要實現的效果也很簡單,就是已登錄的用戶正常顯示,沒有登錄的用戶強制跳轉到登錄頁,重點就在 MainLayout.razor 的 @code{} 裏面

@inherits LayoutComponentBase
@inject NavigationManager nav 
@inject MessageService msg @inject Blazored.LocalStorage.ILocalStorageService storage
@using BlazorLoginDemo.Data <CascadingValue Value="currUser"> <Layout Style="min-height: 100vh; "> <Sider Style="overflow: auto;height: 100vh;position: fixed;left: 0;"> <div style="height:55px; color:white; margin-left:10px;margin-top:5px;"> <Icon Type="github" Width="48" Height="48" Style="vertical-align:middle" /> <span style="font-size:24pt; vertical-align:middle">Blazone</span> </div> <NavMenuAnt /> </Sider> <Layout Class="site-layout" Style=" margin-left: 200px"> <Header Class="site-layout-background"> <LoginControl ChildEvents="(e)=>LogoutEvent(e)"/> </Header> <Content Style="margin: 24px 16px 0; overflow: initial;"> @Body </Content> <Footer Style=" text-align: center;"> Blazone &copy;2021 </Footer> </Layout> </Layout> </CascadingValue> @code{ /// <summary> /// 強制刷新標誌 /// </summary> private bool forceRender { get; set; } = false; private void LogoutEvent(object username) { msg.Info($"See you later {(string)username}");
//通過 LoginControl 組件回調 接收強制刷新消息 forceRender = true; } protected override async Task OnAfterRenderAsync(bool firstRender) { base.OnAfterRender(firstRender); if (firstRender || forceRender ) { forceRender = false; currUser = await CurrentUser.Load(storage); if (null == currUser) nav.NavigateTo("/Login"); else StateHasChanged(); } }
/// <summary> /// 有 CascadingValue 加持, 所有子組件可以通過 [CascadingParameter] 繼承讀取 /// </summary> private CurrentUser currUser { get; set; } }

CurrentUser.Load() 方法就是從 LocalStorage 中把用戶身份信息讀出來

        public static async Task<CurrentUser> Load(ILocalStorageService localStorage)
        {
            var s = await localStorage.GetItemAsync<string>(LOCAL_STORAGE_KEY);
            return fromStorageString(s);
        }

唯一需要注意的是, ILocalStorageService 對象要等到頁面渲染完成以後才能調用,所以只能放在 OnAfterRenderAsync() 裏面,OnInitialize()中調用它是不行的。

最後說一下登錄與登出的操作:

1.登錄只需要在登錄按鈕的 OnClick() 裏面比對用戶名口令,通過就存儲用戶身份信息到 LocalStorage,然後跳轉到默認首頁即可;

2.登出稍微曲折一點,,定製一個 LoginControl.razor 組件用於顯示登錄用戶名和登出按鈕, 在登出按鈕的 OnClick() 中移除 LocalStorage中保存的用戶身份信息,觸發一個ClientEvent 通知 MainLayout.razor 要強制刷新,最後再重新定向到首頁或者登錄頁即可。

 

@page "/loginControl"
@using BlazorLoginDemo.Data
@inject NavigationManager nav
@*@inject Blazored.SessionStorage.ISessionStorageService storage*@
@inject Blazored.LocalStorage.ILocalStorageService storage

@if (null == currUser)
{
     <p style="color:white"><em>Loading...</em></p>
}
else
{
    <div style="text-align:right; color:white;">
        Welcome,<b> @currUser.UserName </b>!
        <Button Type="primary" Shape="round" Size="normal" 
                Icon="logout" OnClick="logout" >退出</Button>
    </div>
}          
@code {
    [CascadingParameter]
    protected CurrentUser currUser{ get; set; }

    [Parameter]
    public EventCallback<string> ChildEvents { get; set; }
    private async Task RaiseEvent()
    {
        if (ChildEvents.HasDelegate)
        {
            await ChildEvents.InvokeAsync(currUser.UserName);
            StateHasChanged();
        }
    }

    private async Task logout()
    {
        await RaiseEvent();

        await CurrentUser.Remove(storage);
        nav.NavigateTo("/");
    }
}

 

至於 LocalStorage 中保存的用戶身份信息要存儲哪些數據,要不要設置登錄有效期,怎麼保護是數字簽名還是AES加密,就按你的喜好自由發揮了。

要是覺得 LocalStorage 一直存着不放心,還有 Blazored.SessionStorage.ISessionStorageService 可以選用,關掉窗口就清空了。

 

參考文獻:

1.Blazor 極簡登錄模型

2.使用 Blazor 開發內部後臺(三):登錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章