Blazor WebAssembly使用 AuthenticationStateProvider 自定义身份认证

news/2024/9/27 9:25:53

本文章以客户端基础,实现类似后台系统,进入后台控制台页面需要经过登录身份验证才可访问情况

简单来时就是实现前后端分离,前端通过 token和用户信息进行身份认证,或者在 AuthenticationStateProvider  实现方法 GetAuthenticationStateAsync 中调用后台接口进行身份验证

安装依赖Microsoft.AspNetCore.Components.AuthorizationBlazored.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; }}

  

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/30512.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

100274. 从魔法师身上吸取的最大能量

在神秘的地牢中,n 个魔法师站成一排。每个魔法师都拥有一个属性,这个属性可以给你提供能量。有些魔法师可能会给你负能量,即从你身上吸取能量。 你被施加了一种诅咒,当你从魔法师 i 处吸收能量后,你将被立即传送到魔法师 (i + k) 处。这一过程将重复进行,直到你到达一个不…

Lua热更学习--使用toLua中的协程

[6] C#访问调table类中的成员变量和函数 访问table中的变量和函数 lua中可以使用table作为class,因此对table中的函数访问调用是必要的根据前面对table访问和function的获取调用,这里尝试获取调用。 依然是如此,此种调用方式获取到的table中的函数是引用拷贝。 Main.lua脚本…

consul部署

下载二进制包 下载地址:https://developer.hashicorp.com/consul/install https://releases.hashicorp.com/consul/1.18.1/consul_1.18.1_linux_amd64.zip下载解压wget https://releases.hashicorp.com/consul/1.18.1/consul_1.18.1_linux_amd64.zip [root@mcw12 mcw]# ls con…

TCP的四次挥手过程

TCP连接是双向传输的对等的模式(全双工模式),就是说双方都可以同时向对方发送或接收数据。而断开的时候,也是双方都可以主动断开,此时需要经过四次挥手的过程,流程如下图所示...TCP连接是双向传输的对等的模式(全双工模式),就是说双方都可以同时向对方发送或接收数据。…

Android开发Kotlin学习笔记

为了做《基于安卓定位的考勤系统》,学了一些杂乱的知识,在这里简单记录一下。除了在C#桌面应用开发中感性的体会到了些XML布局的知识以及课上学习的Java知识,其他也算是零基础了。 Google Android Developer的课程 2023/10/25 :跟着官方文档先快速入门一下基本内容。截至目…

SpringBoot速记

本篇以SpringBoot快速构建一个基础项目,在构建的同时记录相关的知识。常见的架构图: 其中, config中可以引入第三方的jar包 controller中存放控制类一个简单的例子如下: mapper中存放对数据库的操作接口 pojo中是实体对象类,常与数据表对应 service中存放服务类: xml中…

容器技术:优化软件测试流程的利器

前言 你是否曾想过,如何让你的应用程序在任何地方都能够运行,而无需担心各种环境的兼容性问题?之前,我们可能是想着用虚拟机,但是现在我们有了其他选择,不知道你是否听说过容器技术,乍一听却感到有些晦涩难懂?别担心,本文将为你揭开容器技术的神秘面纱,让你轻松理解这…