首页 > 编程语言 > 学习ASP.NET Core Blazor编程系列二十八——JWT登录(3)

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

时间:2023-03-12 12:34:43浏览次数:58  
标签:Core ASP BlazorAppDemo JWT new using Blazor public

学习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)  

十二、实现登入

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

系列文章中学习了使用AuthenticationStateProvider实现模拟登录。今天的文章实现JWT登录,使用WebAPI接口来实现通过JWT令牌登录。

  1. 在Visual Studio 2022的解决方案资源管理器中,鼠标右键单击“BlazorAppDemo”项目名称,在弹出菜单中选择 “添加—>新建文件夹”,并将新建文件夹改为“Api”。如下图。

 

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

 

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;
        }
    }
}

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

using System.Net;
namespace BlazorAppDemo.Models
{
    public class UserToken
    {

        public bool IsSuccess { get ; set; } 
        public HttpStatusCode StatusCode { get; set; }
        public string Token { get; set; }
        public DateTime ExpireTime { get; set; }
     }
}

 

4.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Utils”文件夹,右键单击,在弹出菜单中选择“添加—>类”,在弹出对话框中,将类命名为“TokenManager”。并添加如下代码:
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; } }
    }
}
    5.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Auth”文件夹,右键单击,在弹出菜单中选择“添加—>新建项”,在弹出对话框中,选择“接口”,并将接口命名为“IAuthService”。如下图。并添加如下代码:
using BlazorAppDemo.Models;

namespace BlazorAppDemo.Auth
{

    public interface IAuthService
    {

        Task<UserToken> LoginAsync(UserInfo userInfo);

        Task<UserToken> LogoutAsync();
    }
}

 

6.在Visual Studio 2022的解决方案资源管理器中,鼠标左键选中“Auth”文件夹,右键单击,在弹出菜单中选择“添加—>类”,在弹出对话框中,将类命名为“AuthService”。并添加如下代码:
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)
        {

            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 Task<UserToken> LogoutAsync()
        {
            throw new NotImplementedException();
        }
    }
}

 

LoginAsync登录方法的实现功能:
  • 將账号与密码,发送到AuthController做验证,验证成功生成UserToken实例
  • 将token写到TokenManger实例中
  • 通知前面页面更新登录状态
  • 每次request的header将bearer token都带上。

 

7. 在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); } } }

 

8. 在Visual Studio 2022的解决方案管理器中,使用鼠标左键,双击Program.cs文件,将之在文本编辑器中打开,将我们写的AuthController和框架中的HttpClient,使用DI方式注入,添加Controller服务。具体代码如下:
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;
using BlazorAppDemo.Api;
 
var builder = WebApplication.CreateBuilder(args);
 
 

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
IConfiguration config = ConfigHelper.Configuration;
System.Console.WriteLine(config["ConnectionStrings:BookContext"]);
builder.Services.AddDbContextFactory<BookContext>(opt =>
   opt.UseSqlServer(ConfigHelper.Configuration["ConnectionStrings:BookContext"]));
builder.Services.AddScoped<ImitateAuthStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(implementationFactory =>
implementationFactory.GetRequiredService<ImitateAuthStateProvider>());
builder.Services.AddScoped<JwtSecurityTokenHandler>();
//此处的url地址改成自己实际的地址

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://localhost:7110") });
 
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<AuthController>();
//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)
    };
});
;
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.MapControllers();

 
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.UseAuthentication();
app.UseAuthorization();

 
app.Run();

 

 

9. 在Visual Studio 2022的菜单栏上,找到“调试-->开始调试”或是按F5键,Visual Studio 2022会生成BlazorAppDemo应用程序,并在浏览器使用Rest调试插件,对api/auth/login接口进行调试,只要登入成功就可以取得token。如下图。

 

 

10.我们在用户名输入框中输入用户名"admin",在密码输入框中输入密码"111111",点击“登录”按钮,进行登录。我们进入了系统。如下图。

 

标签:Core,ASP,BlazorAppDemo,JWT,new,using,Blazor,public
From: https://www.cnblogs.com/chillsrc/p/17207969.html

相关文章

  • EntityFramworkCore7笔记
    转载  编写和拼接大量的SQL语句.这样做很容易出错,且容易发生SQL注入的风险.同时由于数据库的数据类型和语言的数据类型不一致,我们需要手动对数据类型进行转换,......
  • asp.net mvc5部署到IIS 403 - 禁止访问: 访问被拒绝。
    asp.netmvc5部署到IIS403-禁止访问:访问被拒绝。各种检查,修改web.config,权限...都无果此时,检查一下你项目下是否缺少Global.asax文件......
  • nacos实现Java和.NetCore的服务注册和调用
    用nacos作为服务注册中心,如何注册.NetCore服务,如何在Java中调用.NetCore服务呢?可以分为下面几个步骤: 0.运行nacos 1.开发.netcore服务,然后调用nacos提供的.netcore......
  • 【ASP.NET Core】修改Blazor.Server的Hub地址后引发的问题
    BlazorServer,即运行在服务器上的Blazor应用程序,它的优点是应用程序在首次运行时,客户端不需要下载运行时。但它的代码是在服务器上执行的,然后通过SignalR通信来更新客......
  • 遭遇奇怪的问题:所有 ASP.NET Core ViewComponent 都输出为空
    3月9日晚上的一次发布中遇到一个非常奇怪的问题,发布前在staging环境测试正常,发布到生产环境后发现所有ViewComponent都输出为空(没有任何内容)。生产环境与staging环......
  • 【HMS Core】运动健康服务指标权限问题
    ​ 【关键字】运动健康服务、指标权限 【问题背景】开通了运动健康部分指标权限,但是APP授权页面只展示部分,展示不全面​​【问题分析】发生此种情况,可能有两个......
  • C# ASP.NET MVC 配置允许跨域访问
    在web.config文件中的system.webServer节点下增加如下配置<httpProtocol><customHeaders><addname="Access-Control-Allow-Origin"value="*"/>......
  • ASP.NET Core - 配置系统之配置提供程序
    3.配置提供程序上面提到,通过IConfigurationBuilder的实现类对象,我们可以自由地往配置系统中添加不同的配置提供程序,从而获取不同来源的配置信息。.NETCore中,微软提供......
  • 如何在 Net6.0 中对 WebAPI 进行 JWT 认证和授权
    一、简介我们做微服务开发,或者说做分布式开发,有一项技术我们是避不开的,那就是WebAPI,在Net6.0中,有两类WebAPI,一类是极简WebAPI,它砍掉了很多冗余的东西,更纯粹的......
  • .net core 项目内网IP访问设置
     修改applicationhost.config文件夹,增加一条电脑IP访问地址(记得IP需要更换为自己电脑IP,端口和localhost相同)<bindings> <bindingprotocol="http"bindingInfo......