asp.net core 中的Jwt(Json Web Token)的使用详解

ASP.NET Core 中的 JWT (Json Web Token) 的使用详解

什么是 JWT?

JWT 是一种轻量级的身份验证和授权解决方案,它是为 Web 应用程序设计的,基于 JSON 形式的轻量级开放标准(RFC 7519)。

其特点在于:

  • 可以使用一个 token 进行身份验证和授权,避免了复杂的 Sessions 或者 Cookies 的管理。
  • Token 能够被服务器解密和验证签名,防止黑客入侵。
  • Token 可以包含一些用户信息,可以可靠地完成身份验证,并授权服务器访问受保护的资源。

JWT 的结构

JWT 由三部分组成:头部,载荷和签名。

头部,Header

头部的格式是一个 JSON 对象,由两个属性组成:alg(algorithm) 和 typ (type)。

alg 指定了签名和加密的算法,例如 HMAC SHA256 和 RSA,以及对应的密匙。

{
  "alg": "HS256",
  "typ": "JWT"
}

载荷,Payload

载荷也是一个 JSON 对象,它包含了用户的身份信息、授权相关信息和其他额外的参数。它并不是加密的,任何人都可以读取它,因此不应该包含敏感信息。 JWT 的官方规定了一些预定义的声明,在对象中使用这些声明即可:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

签名,Signature

签名使用了加密机制,它需要服务器的密钥才能时做到正常解密和验证。将头部和载荷都用 Base64 编码后,在它们之间加上字符串类型的密钥进行 HMAC SHA256 串行化后的值尾部添加后即可。

头部与载荷的 Base64 的编码后的字符串格式:

eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkpvaG4gRG9lIiwgImlhdCI6IDE1MTYyMzkwMjJ9

加了密的字符串格式:

eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkpvaG4gRG9lIiwgImlhdCI6IDE1MTYyMzkwMjJ9.4l8SXMIzawtS2OUTxDiXamPLHY0pRHChDNdUnlN0Qv8

ASP.NET Core 中 JWT 的使用

ASP.NET Core 提供了一个 JWT 包,可以通过 NuGet 安装使用,这个包包含了 JWToken 中的完整实现。

添加 JWT 依赖包

为了使用 JWT,需要在项目中添加 Microsoft.AspNetCore.Authentication.JwtBearer 包的依赖,这个包是 ASP.NET Core 中处理 JWT 的核心包。

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

注册 JWT 中间件

在 Startup.cs 文件中注册 JWT 中间件,它会拦截进入应用程序的 HTTP 请求:

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("Jwt:Key").Value)),
        ValidateIssuer = false,
        ValidateAudience = false
    };
});

其中,件保存了几个配置信息,包括:

  • 需要 HTTPS
  • 需要保存 Token
  • Token 认证参数
    • ValidateIssuerSigningKey: 是否需要验证签名
    • IssuerSigningKey: 签名密钥
    • ValidateIssuer: 是否需要验证签发者
    • ValidateAudience: 是否需要验证观众

配置 JWT 配置文件

在应用中,我们可以设置一些固定变量或者不能随意变更的信息,如 HttpsMetaData, TokenValidation Parameters 等等。

可以设置一个 appsettings.json 文件来定义 JWT 中间件所需的必要信息:

{
  "Jwt": {
    "Key": "this_is_my_super_secure_key_123",
    "Issuer": "acnodesoft.com"
  }
}

需要注册配置文件:

services.Configure<JwtSettings>(Configuration.GetSection("Jwt"));

生成 JWT

使用 NuGet 的 System.IdentityModel.Tokens.Jwt pakcage 来生成 JWT。

private string GenerateToken(User user)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_jwtSettings.Key);
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new Claim[] 
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Username)
        }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

其中,CreateToken 方法将两个参数串联在一起并使用对设置好的 Secret 指定的算法生成了最终的 JWT。经过 Base64 编码 (不是加密!) 后 JWT 可以被发送到客户端来使用。

这些配置可以灵活的修改和适配项目需求,然后利用 JWT 类中的方法即可实现 Token 的生成。

验证和使用 JWT

验证 JWT 的过程很简单:

[Authorize]
[HttpGet("profiles/{id}")]
public async Task<IActionResult> GetProfileById(int id)
{
    var user = await _userRepository.GetUserWithProfile(id);
    if (user == null) return NotFound();

    var profile = user.Profile;
    return Ok(new { profile.DisplayName, profile.Headline, profile.Location });
}

这时,需要所定义的 Authorization 机制,使用 [Authorize] 属性。

如果请求里有一个正确格式的 JWT,它会被拦截,否则请求返回 401。

示例1: 使用 JWT 单点登录

示例1,假设有A网站和B网站,它们的用户是相互独立的,但是它们共享相同的用户。例如,同一家公司的员工在两个不同的应用中使用相同的用户配置。

为了实现这个实例,需要创建一个单独的用户身份验证系统,这个系统产生的 JWT 将会被 A 和 B 网站共享。

步骤:

  • 每次用户通过我们单独的认证系统进行身份验证、授权时,该系统都会颁发一个 JWT
  • A、B 网站不再使用本地的身份验证机制,而是转移到调用单独的认证系统。
  • 当客户端访问 A 网站时,客户端带着 JWT 访问单独的认证系统,认证系统检查 JWT 的签名、有效期,并验证用户信息。如果所有条件都符合,就颁发一个新的 JWT 给客户端。
  • 客户端再从 B 网站请求数据时,带着它从单独的认证系统获取的 JWT。

相对于原来的方案而言,SSO大大简化了应用程序的身份验证和授权流程,使应用程序编写工作更简便,轻松和快速地实现各种身份验证和授权功能。本方案是一个非常棒的示例,展示了使用 JWT 实现身份验证的最佳实践,特别是在使用多个网站进行 SSO 的情况下。

示例2:使用 JWT 保护 API

API 为企业提供了一个通用的服务实例,比如向外部调用者提供数据或者向设备提供命令,因此 API 的安全性显得尤为重要。可以使用 JWT 保护 Web API。

步骤:

  1. 在 API 控制器上添加 JWT 身份验证机制。添加 [Authorize] 属性。
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/Todo
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
    {
        return await _context.TodoItems.ToListAsync();
    }

    // GET: api/Todo/5
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return todoItem;
    }

    // PUT: api/Todo/5
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
    {
        if (id != todoItem.Id)
        {
            return BadRequest();
        }

        _context.Entry(todoItem).State = EntityState.Modified;
        await _context.SaveChangesAsync();

        return NoContent();
    }

    // POST: api/Todo
    [HttpPost]
    public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
    {
        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
    }

    // DELETE: api/Todo/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }
}
  1. 生成和发送 JWT
     services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
        {
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("Jwt:Key").Value)),
                ValidateIssuer = false,
                ValidateAudience = false,
                ClockSkew = TimeSpan.Zero
            };
        });

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

在 Controller 使用原代码即可。

以上就是 ASP.NET Core 中 JWT 使用的全部步骤了。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:asp.net core 中的Jwt(Json Web Token)的使用详解 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • Windows Server2012 安装配置DNS服务器方法详解

    下面是关于“Windows Server 2012安装配置DNS服务器方法详解”的完整攻略,包含两个示例。 1. DNS服务器简介 DNS(Domain Name System)是互联网上的一种命名系统,用于将域名转换为IP地址。DNS服务器是运行DNS服务的计算机,它负责将域名解析为IP地址。在Windows Server 2012中,可以使用DNS服务器…

    C# 2023年5月15日
    00
  • 如何在C#中使用Dapper ORM

    下面是如何在C#中使用Dapper ORM的完整攻略,包含两个示例说明。 Dapper ORM 简介 Dapper ORM 是 .NET 开发中常用的一个轻量级 ORM 框架,它由 StackExchange 团队在开发 StackOverflow 期间所使用的 ORM 技术衍生而来,旨在提供更快、更简单的数据访问体验。 Dapper ORM 安装 Dapp…

    C# 2023年5月31日
    00
  • C# 通过反射获取类型的字段值及给字段赋值的操作

    C#通过反射获取类型的字段值及给字段赋值的操作,可以通过以下步骤进行: 1. 获取类型对象 获取类型对象可以通过两种方式进行,一种是通过已知对象获取,另一种是通过类型名称字符串获取。以下是两种方式的示例代码: 通过已知对象获取 MyClass obj = new MyClass(); Type type = obj.GetType(); 通过类型名称字符串获…

    C# 2023年5月15日
    00
  • C#泛型实例详解

    C#泛型实例详解 本文将详细讲解C#泛型的使用方法与实例,并通过两个示例进行演示。 什么是泛型 泛型在C#中的作用类似于Java中的模板,它能够将具体的数据类型参数化,使得类或者方法可以适应多种不同类型的数据。 使用泛型还有以下优点: 提高程序的可读性和可维护性,减少重复的代码 编译时类型安全,避免因类型错误导致的运行时异常 避免了装箱和拆箱操作,提高了程序…

    C# 2023年5月15日
    00
  • ASP.NET Identity的基本用法

    以下是“ASP.NET Identity的基本用法”的完整攻略: 什么是ASP.NET Identity ASP.NET Identity是一个用于管理用户身份和授权的框架。它提供了组API,可以轻松地将身份验证和授权功能添加到ASP.NET应用程序中。ASP.NET Identity持多种身份验证方法,包括用户名/密码、外部登录、双因素身份验证等。 ASP…

    C# 2023年5月12日
    00
  • C#使用系统方法发送异步邮件完整实例

    下面是C#使用系统方法发送异步邮件的完整攻略: 1.前置知识 在学习使用C#发送异步邮件之前,你需要掌握如下知识: C#基础知识,包括语法和常见数据类型; SMTP协议知识,包括SMTP服务器地址、端口、用户名和密码等。 2.引入命名空间 首先,我们需要在C#代码中引入命名空间 System.Net.Mail,因为该命名空间包含了SMTP协议的相关类和方法:…

    C# 2023年6月7日
    00
  • c# 模拟串口通信 SerialPort的实现示例

    下面是关于“C#模拟串口通信SerialPort的实现示例”的攻略: 第一步:准备工作 在实现具体的代码之前,需要先准备一些基础工作。包括: 准备一个模拟串口的环境。这可以通过安装一个虚拟串口软件来实现(如“虚拟串口驱动程序”) 引入SerialPort类。在程序中需要使用System.IO.Ports命名空间,可以通过在程序中添加以下引用来实现:using…

    C# 2023年6月6日
    00
  • 关于.NET异常处理的思考总结

    以下是关于.NET异常处理的思考总结的攻略: 1. 前言 .NET是一种广泛使用的编程框架,用于开发各种类型的应用程序。在开发应用程序时,很难避免不出现错误和异常。为了确保应用程序正常运行,必须合理处理这些异常。本文将探讨.NET异常处理的思考总结。 2. 异常的基本概念 异常是指在应用程序中出现的意外结果或错误,也称为运行时错误或未处理异常。异常通常由编程…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部