隐藏

简单粗暴的实现 Blazor Server 登录鉴权

发布:2022/4/27 13:56:37作者:管理员 来源:本站 浏览次数:1564


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