草庐IT

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

DotNet菜园 2023-03-28 原文
学习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;
        }
    

        /// /// <summary>
        /// 从令牌中获取数据声明
        /// </summary>
        /// <param name="token">令牌</param>
        /// <returns></returns>
        public IEnumerable<Claim> ParseToken(string token)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validateParameter = ValidParameters();
            token = token.Replace("Bearer ", "");
            try
            {
                tokenHandler.ValidateToken(token, validateParameter,
 out SecurityToken validatedToken);
                var jwtToken = tokenHandler.ReadJwtToken(token);
                return jwtToken.Claims;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }
}
}

 

 

 

 

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。如下图。

 

 

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

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  3. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  4. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  5. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  6. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  7. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  8. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  9. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  10. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

随机推荐