十三、实现登出

至此关于Blazor的内容,先写到这里, 我们基本上完成了登入、增加、删除、查询、修改等功能,应对一般的应用,已经足够。今天实现登录功能。有登入,必然要有登出,本文我们来介绍一下如何登出。

1. 在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Pages”文件夹,右键单击,在弹出菜单中选择“添加—>Razor组件…”,并将组件命名为“Logout.razor”。登出组件的功能是用于退出登入,返回首面。其代码如下:

@page "/Logout"
@using BlazorAppDemo.Auth;
@inject IAuthService authService
@inject NavigationManager navigation @code {
protected override async Task OnInitializedAsync()
{ await authService.LogoutAsync();
navigation.NavigateTo("/");
} }
2. 在Visual Studio 2022的解决方案管理器中,使用鼠标左键,双击TokenManager.cs文件,对代码进行修改。具体代码如下:

using BlazorAppDemo.Models;
using System.Collections.Concurrent; namespace BlazorAppDemo.Utils
{ public class TokenManager
{ private const string TOKEN = "authToken"; private static readonly ConcurrentDictionary<string, UserToken> tokenManager;
static TokenManager()
{
tokenManager=new ConcurrentDictionary<string, UserToken>();
} public static ConcurrentDictionary<string, UserToken> Instance { get { return tokenManager; } } public static string Token { get { return TOKEN; } } public static bool RemoveToken(string token)
{
if (tokenManager.TryRemove(token,out UserToken delUserToken))
{
Console.WriteLine($"delete token {delUserToken.Token}");
return true;
}
else
{ Console.WriteLine($"unable delete token {delUserToken.Token}");
return false;
}
}
}
}

3.在Visual Studio 2022的解决方案资源管理器中,鼠标左键双击“Api”文件夹中的 “AuthController.cs”文件,将此文件中的Logout方法的代码补全。代码如下:

using BlazorAppDemo.Models;
using BlazorAppDemo.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text; namespace BlazorAppDemo.Api
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IJWTHelper jwtHelper; public AuthController(IJWTHelper _IJWTHelper)
{
this.jwtHelper = _IJWTHelper; } [HttpPost("Login")]
public async Task<ActionResult<UserToken>> Login(UserInfo userInfo)
{
//Demo用
if (userInfo.UserName == "admin" && userInfo.Password == "111111")
{
return BuildToken(userInfo);
}
else
{
UserToken userToken = new UserToken()
{
StatusCode = System.Net.HttpStatusCode.Unauthorized,
IsSuccess = false };
return userToken;
}
} /// <summary>
/// 建立Token
/// </summary>
/// <param name="userInfo"></param>
/// <returns></returns>
private UserToken BuildToken(UserInfo userInfo)
{ string jwtToken = jwtHelper.CreateJwtToken<UserInfo>(userInfo); //建立UserToken,回传客户端
UserToken userToken = new UserToken()
{
StatusCode = System.Net.HttpStatusCode.OK,
Token = jwtToken,
ExpireTime = DateTime.Now.AddMinutes(30),
IsSuccess= true };
return userToken;
} [HttpGet("Logout")]
public async Task<ActionResult<UserToken>> Logout()
{
bool flag= TokenManager.RemoveToken(TokenManager.Token); var response = new UserToken();
response.IsSuccess = !flag;
return response;
}
}
}

4.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Auth”文件夹中的 “AuthService.cs”文件,将此文件中的LogoutAsync方法中添加如下代码:

using BlazorAppDemo.Models;
using BlazorAppDemo.Utils;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Concurrent;
using System.Net.Http;
using System.Text; namespace BlazorAppDemo.Auth
{ public class AuthService : IAuthService
{
private readonly HttpClient httpClient;
private readonly AuthenticationStateProvider authenticationStateProvider;
private readonly IConfiguration configuration;
private readonly Api.AuthController authController;
private readonly string currentUserUrl, loginUrl, logoutUrl; public AuthService( HttpClient httpClient, AuthenticationStateProvider authenticationStateProvider,
IConfiguration configuration,Api.AuthController authController)
{
this.authController = authController;
this.httpClient = httpClient;
this.authenticationStateProvider = authenticationStateProvider;
this.configuration = configuration;
currentUserUrl = configuration["AuthUrl:Current"] ?? "Auth/Current/"; loginUrl = configuration["AuthUrl:Login"] ?? "api/Auth/Login";
logoutUrl = configuration["AuthUrl:Logout"] ?? "/api/Auth/Logout/";
} public async Task<UserToken> LoginAsync(UserInfo userInfo)
{
response.Content.ReadFromJsonAsync<UserToken>();
var result = authController.Login(userInfo); var loginResponse = result.Result.Value; if (loginResponse != null && loginResponse.IsSuccess)
{
TokenManager.Instance.TryAdd(TokenManager.Token, loginResponse);
((ImitateAuthStateProvider)authenticationStateProvider).NotifyUserAuthentication(loginResponse.Token); httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer",
loginResponse.Token); return loginResponse;
}
return new UserToken() { IsSuccess = false };
} public async Task<UserToken> LogoutAsync()
{
var result = authController.Logout();
var logoutResponse = result.Result.Value;
((ImitateAuthStateProvider)authenticationStateProvider).NotifyUserLogOut();
httpClient.DefaultRequestHeaders.Authorization = null;
return logoutResponse;
}
} }
LogoutAsync方法:

  • 将token从TokenManger实例中移除
  • 通知前面页面更新登录状态
  • 将request中的header参数bearer token移除。

5. 在Visual Studio 2022的解决方案管理器中,使用鼠标左键,双击ImitateAuthStateProvider.cs文件,对代码进行修改。具体代码如下:

using BlazorAppDemo.Models;
using BlazorAppDemo.Utils;
using Microsoft.AspNetCore.Components.Authorization;
using System.Net.Http;
using System.Security.Claims; namespace BlazorAppDemo.Auth
{
public class ImitateAuthStateProvider : AuthenticationStateProvider
{
private readonly IJWTHelper jwt;
private AuthenticationState anonymous;
private readonly HttpClient httpClient; public ImitateAuthStateProvider(IJWTHelper _jwt, HttpClient httpClient)
{
anonymous = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
jwt = _jwt;
this.httpClient = httpClient;
} bool isLogin = false;
string token = string.Empty;
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
//确认是否已经登录
UserToken userToken;
TokenManager.Instance.TryGetValue(TokenManager.Token,out userToken);
string tokenInLocalStorage=string.Empty;
if (userToken != null)
{
tokenInLocalStorage = userToken.Token;
} if (string.IsNullOrEmpty(tokenInLocalStorage))
{
//沒有登录,则返回匿名登录者
return Task.FromResult(anonymous);
} //將token取出转换为claim
var claims = jwt.ParseToken(tokenInLocalStorage); //在每次request的header中都将加入bearer token
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer",
tokenInLocalStorage);
//回传带有user claim的AuthenticationState return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt")))); }
public void Login(UserInfo request)
{
//1.验证用户账号密码是否正确
if (request == null)
{
isLogin=false;
}
if (request.UserName == "user" && request.Password == "111111") {
isLogin = true;
token= jwt.CreateJwtToken<UserInfo>(request);
Console.WriteLine($"JWT Token={token}");
} NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
} public void NotifyUserAuthentication(string token)
{ var claims = jwt.ParseToken(token);
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt"));
var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
NotifyAuthenticationStateChanged(authState);
} public void NotifyUserLogOut()
{
var authState = Task.FromResult(anonymous);
NotifyAuthenticationStateChanged(authState);
} }
}
6. 在Visual Studio 2022的解决方案管理器中,使用鼠标左键,双击MainLayout.razor文件,对代码进行修改。具体代码如下:

@using BlazorAppDemo.Pages
@inherits LayoutComponentBase <PageTitle>BlazorAppDemo</PageTitle> <div class="page">
<div class="sidebar">
<NavMenu />
</div> <main>
<AuthorizeView>
<Authorized>
<div class="top-row px-4"> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
<div class ="col-3 oi-align-right">
你好, @context.User.Identity.Name!<a href="/Logout">Logout</a>
</div>
</div> <article class="content px-4">
@Body
</article> </Authorized>
<NotAuthorized>
<div style="margin: 120px 0; width:100%; text-align: center; color: red;"> <span style="font-size:20px">检测到登录超时,请重新<a href="/login" style="text-decoration:underline">登录</a>!

</span>
</div>
<RedirectToLogin></RedirectToLogin>
</NotAuthorized>
</AuthorizeView> </main>
</div>

7. 在Visual Studio 2022的菜单栏上,找到“调试-->开始调试”或是按F5键,Visual Studio 2022会生成BlazorAppDemo应用程序。浏览器会打开登录页面。我们在登录页面的用户名输入框中输入用户名,在密码输入框中输入密码,点击“登录”按钮,进行登录。我们进入了系统,在页面的右上角处,会出现登录用户的用户名,与一个“Logout”按钮。如下图。

学习ASP.NET Core Blazor编程系列三十——JWT登录(4)的更多相关文章

  1. 学习ASP.NET Core Blazor编程系列二十二——登录(1)

    学习ASP.NET Core Blazor编程系列文章之目录 学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应 ...

  2. 学习ASP.NET Core Blazor编程系列二十——文件上传(完)

    学习ASP.NET Core Blazor编程系列文章之目录 学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应 ...

  3. 022年9月12日 学习ASP.NET Core Blazor编程系列三——实体

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  4. 学习ASP.NET Core Blazor编程系列二十三——登录(2)

    学习ASP.NET Core Blazor编程系列文章之目录 学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应 ...

  5. 学习ASP.NET Core Blazor编程系列二十三——登录(3)

    学习ASP.NET Core Blazor编程系列文章之目录 学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应 ...

  6. 学习ASP.NET Core Blazor编程系列四——迁移

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  7. 学习ASP.NET Core Blazor编程系列五——列表页面

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  8. 学习ASP.NET Core Blazor编程系列六——初始化数据

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  9. 学习ASP.NET Core Blazor编程系列六——新增图书(上)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  10. 学习ASP.NET Core Blazor编程系列八——数据校验

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

随机推荐

  1. FreeSql 将 Saas 租户方案精简到极致[.NET ORM]

    什么是多租户 维基百科:"软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务".一个租户是一组共享该软件实例特定权限的用户.有了多租户架构 ...

  2. openSUSE 播放使用VLC播放视频

    openSUSE 使用VLC播放视频 linux视频播放 为什么 通常我们在安装号vlc后,由于版权的原因,是无法获取视频的解码器的.我们需要下载第三方的解码器帮助我们进行解码. 过程如下: 添加pa ...

  3. DHCP 服务详解

    本文转发于华为IP知识百科,链接地址 DHCP 目录 一.什么是DHCP? 二.为什么要使用DHCP? 三.DHCP是怎么工作的 四.DHCP使用场景 一.什么是DHCP? 动态主机配置协议DHCP( ...

  4. ethcat开发记录 一

    一.方案 1.移植开源方案SOEM 2.专用芯片 二.SOEM移植 (一)硬件 stm32f407,168M PHY:LAN8720A (ii) Points to note 1, the PHY a ...

  5. WPF Binding表达式

    前言: WPF BindingBinding表达式的使用,可以很方便的绑定参数和更新界面数据. 1.界面添加控件,并设置对应属性的Binding表达式,例如: <Window x:Class=& ...

  6. HTTP请求向服务器传参方式

    请求HttpRequest 提示: 用户发送请求时携带的参数后端需要使用,而不同的发送参数的方式对应了不同的提取参数的方式 所以要学会如何提取参数,我们就需要先了解前端传参数有哪些方式 回想一下,利用 ...

  7. JAVA——》微信分账

    做一个推荐分享的功能,场景:每推荐成功奖励推荐人一定的推荐金. 这里,我就用调用了微信支付分账接口.链接:https://pay.weixin.qq.com/wiki/doc/api/allocati ...

  8. SpringBoot加载相关注解

    springBoot加载 @Configuration 表明该类是一个配置类常常配合@Bean使用,让容器管理对象 @Configuration(proxyBeanMethods = true) pr ...

  9. CSS设置边距

    1.内边距 所有的 ​HTML ​元素基本都是以矩形为基础. 每个 HTML 元素周围的矩形空间由三个重要的属性来控制: ​padding(内边距)​ ​margin(外边距)​ ​border(边框 ...

  10. MySQL 面试题总结

    MySQL的面试知识点总结 Q1:MySQL 的逻辑架构了解吗? 第一层是服务器层,主要提供连接处理.授权认证.安全等功能. 第二层实现了 MySQL 核心服务功能,包括查询解析.分析.优化.缓存以及 ...