- A+
所属分类:.NET技术
接上文学习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。如下图。