• 简单粗暴的实现 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 开发内部后台(三):登录

  • 相关阅读:
    c 的内存分配与释放原则: 通常应遵循“谁malloc,谁free”的原则。
    总算知道怎样从ImageMagick生成的数据转换成HICON: MagickGetImageBlob & LookupIconIdFromDirectoryEx
    收藏:Non-direct与direct ByteBuffer区别
    java NIO 直接与非直接缓冲区
    [收藏]:[算法]LRU和LFU的区别
    异步IO的并发能力:backlog的配置很重要
    ByteBuffer: 当由一个byte[]来生成一个固定不变的ByteBuffer时,使用ByteBuffer.wrap(byte[]);
    ByteBuffer的allocate与allocateDirect2013-01-11
    Windows完成端口与Linux epoll技术简介
    Java并发——Fork/Join框架与ForkJoinPool
  • 原文地址:https://www.cnblogs.com/towerbit/p/15044935.html
Copyright © 2020-2023  润新知