学习ASP.NET Core Blazor编程系列二十七——JWT登录(2),学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(上)


学习ASP.NET Core Blazor编程系列文章之目录
学习ASP.NET Core Blazor编程系列一——综述
学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(上)

学习ASP.NET Core Blazor编程系列三——实体
学习ASP.NET Core Blazor编程系列五——列表页面
学习ASP.NET Core Blazor编程系列七——新增图书
学习ASP.NET Core Blazor编程系列八——数据校验
学习ASP.NET Core Blazor编程系列十三——路由(完)
学习ASP.NET Core Blazor编程系列十五——查询
学习ASP.NET Core Blazor编程系列十六——排序
学习ASP.NET Core Blazor编程系列二十——文件上传(完)
学习ASP.NET Core Blazor编程系列二十一——数据刷新
 学习ASP.NET Core Blazor编程系列二十二——登录(1)
 
   接上文学习ASP.NET Core Blazor编程系列二十七——JWT登录(1) ,我们继续实现功能。

     5.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Utils”文件夹,右键单击,在弹出菜单中选择“添加—>新建项”,在弹出对话框中,选择“接口”,并将接口命名为“IJWTHelper”。如下图。并添加如下代码:

using Microsoft.IdentityModel.Tokens; using System.Security.Claims; namespace BlazorAppDemo.Utils { public interface IJWTHelper { string CreateJwtToken<T>(T user); T GetToken<T>(string Token); IEnumerable<Claim> ParseToken(string token); string? ValidateJwtToken(IEnumerable<Claim> jwtToken); TokenValidationParameters ValidParameters(); } }

 

6.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Utils”文件夹,右键单击,在弹出菜单中选择“添加—>类”,在弹出对话框中,并将类命名为“JWTHelper”。并继承IJWTHelper接口,添加如下代码:

 

using BlazorAppDemo.Models; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Reflection; using System.Security.Claims; using System.Text; namespace BlazorAppDemo.Utils { public class JWTHelper : IJWTHelper { private readonly IConfiguration _configuration; private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler; public JWTHelper(IConfiguration configuration, JwtSecurityTokenHandler jwtSecurityTokenHandler) { _configuration = configuration; _jwtSecurityTokenHandler = jwtSecurityTokenHandler; } /// <summary>
        /// 创建加密JwtToken /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>

        public string CreateJwtToken<T>(T user) { var signingAlogorithm = SecurityAlgorithms.HmacSha256; var claimList = this.CreateClaimList(user); //Signature //取出私钥并以utf8编码字节输出
            var secretByte = Encoding.UTF8.GetBytes(_configuration["Authentication:SecretKey"]); //使用非对称算法对私钥进行加密
            var signingKey = new SymmetricSecurityKey(secretByte); //使用HmacSha256来验证加密后的私钥生成数字签名

            var signingCredentials = new SigningCredentials(signingKey, signingAlogorithm); //在 RFC 7519 规范中(Section#4),一共定义了 7 个预设的 Claims。 //生成Token
            var Token = new JwtSecurityToken( issuer: _configuration["Authentication:Issuer"], //发布者
            audience: _configuration["Authentication:Audience"], //接收者
            claims: claimList, //存放的用户信息
            notBefore: DateTime.UtcNow, //发布时间
            expires: DateTime.UtcNow.AddDays(1), //有效期设置为1天
            signingCredentials //数字签名
 ); //生成字符串token
            var TokenStr = new JwtSecurityTokenHandler().WriteToken(Token); return TokenStr; } public T GetToken<T>(string Token) { Type t = typeof(T); object objA = Activator.CreateInstance(t); var b = _jwtSecurityTokenHandler.ReadJwtToken(Token); foreach (var item in b.Claims) { PropertyInfo _Property = t.GetProperty(item.Type); if (_Property != null && _Property.CanRead) { _Property.SetValue(objA, item.Value, null); } } return (T)objA; } /// <summary>
        /// 创建包含用户信息的CalimList /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>

        private List<Claim> CreateClaimList<T>(T authUser) { var Class = typeof(UserInfo); List<Claim> claimList = new List<Claim>(); foreach (var item in Class.GetProperties()) { if (item.Name == "Password") { continue; } claimList.Add(new Claim(ClaimTypes.Name, Convert.ToString(item.GetValue(authUser)))); } return claimList; } } }

 

7. 在Visual Studio 2022的解决方案资源管理器中,使用鼠标左键双击“Auth”文件夹中的“ImitateAuthStateProvider.cs”文件,在文本编辑器中打开,对代码进行修改。具体代码如下:

using BlazorAppDemo.Models; using BlazorAppDemo.Utils; using Microsoft.AspNetCore.Components.Authorization; using System.Security.Claims; namespace BlazorAppDemo.Auth { public class ImitateAuthStateProvider : AuthenticationStateProvider { private readonly IJWTHelper jwt; public ImitateAuthStateProvider(IJWTHelper _jwt) => jwt = _jwt; //DI

        bool isLogin = false; string token = string.Empty; public override Task<AuthenticationState> GetAuthenticationStateAsync() { if (isLogin) { var claims = new List<Claim>() { new Claim(ClaimTypes.Name,"user"), new Claim(ClaimTypes.Role, "admin") }; var anonymous = new ClaimsIdentity(claims, "testAuthType"); return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(anonymous))); } else { var anonymous = new ClaimsIdentity(); return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(anonymous))); } } 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()); } } }

 

8.在Visual Studio 2022的解决方案管理器中,使用鼠标左键,双击Program.cs文件,将之在文本编辑器中打开,将我们写的JWTHelper与JwtSecurityTokenHandler、使用DI方式注入,添加JWT认证服务。具体代码如下:

using BlazorAppDemo.Data; using BlazorAppDemo.Models; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Components.Authorization; using BlazorAppDemo.Auth; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; using System.IdentityModel.Tokens.Jwt; using BlazorAppDemo.Utils; var builder = WebApplication.CreateBuilder(args); // Add services to the container.
 builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton<WeatherForecastService>(); System.Console.WriteLine(ConfigHelper.Configuration["ConnectionStrings:BookContext"]); builder.Services.AddDbContextFactory<BookContext>(opt => opt.UseSqlServer(ConfigHelper.Configuration["ConnectionStrings:BookContext"])); //builder.Services.AddScoped<AuthenticationStateProvider, ImitateAuthStateProvider>();
 builder.Services.AddScoped<ImitateAuthStateProvider>(); builder.Services.AddScoped<AuthenticationStateProvider>(implementationFactory => implementationFactory.GetRequiredService<ImitateAuthStateProvider>()); builder.Services.AddScoped<JwtSecurityTokenHandler>(); //JWT //JWT认证
 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => { //取出私钥
    var secretByte = Encoding.UTF8.GetBytes(builder.Configuration["Authentication:SecretKey"]); options.TokenValidationParameters = new TokenValidationParameters() { //验证发布者
        ValidateIssuer = true, ValidIssuer = builder.Configuration["Authentication:Issuer"], //验证接收者
        ValidateAudience = true, ValidAudience = builder.Configuration["Authentication:Audience"], //验证是否过期
        ValidateLifetime = true, //验证私钥
        IssuerSigningKey = new SymmetricSecurityKey(secretByte) }; }); //自己写的Jwt 扩展
builder.Services.AddScoped<IJWTHelper,JWTHelper>(); var app = builder.Build(); // Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
 app.UseHsts(); } using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; try { Console.WriteLine("数据库开始初始化。"); var context = services.GetRequiredService<BookContext>(); // requires using Microsoft.EntityFrameworkCore;
 context.Database.Migrate(); // Requires using RazorPagesMovie.Models;
 SeedData.Initialize(services); Console.WriteLine("数据库初始化结束。"); } catch (Exception ex) { var logger = services.GetRequiredService<ILogger<Program>>(); logger.LogError(ex, "数据库数据初始化错误."); } } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.UseAuthentication(); app.UseAuthorization(); app.Run(); 

9.在Visual Studio 2022的菜单栏上,找到“调试–>开始调试”或是按F5键,Visual Studio 2022会生成BlazorAppDemo应用程序,浏览器中会Login登录页面。

10.我们在用户名输入框中输入用户名,在密码输入框中输入密码,点击“登录”按钮,进行模拟登录。我们进入了系统。并且生成了JWT Token。如下图。