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日

相关文章

  • .NET中的属性用法分析

    .NET中的属性用法分析 属性是.NET框架中的一个关键特性,它提供了一种在运行时为对象附加元数据以及在对象上设置特定行为的机制。本文将深入介绍属性的用法分析。 属性的定义 属性定义与函数定义的核心区别在于,属性指定了用于获取或设置值的特定方法。 如下是一个示例: public class Person { private string name; publ…

    C# 2023年5月31日
    00
  • 详解c# 数组(Array)

    详解C#数组(Array) 概述 C#数组是一组相同类型元素的有序集合,可以通过数组下标来访问每一个元素。在C#中,数组是一种按照顺序存储和访问一组元素的结构,数组的下标从0开始,最大下标为数组长度减1。数组是C#中最常用的数据结构之一,能够有效地存储和处理大量数据。 创建和初始化数组 创建数组的语法如下: type[] arrayName; 其中,type…

    C# 2023年5月31日
    00
  • 解决Netcore磊科无线路由器192.168.1.1打不开的方法

    如果您无法通过浏览器访问Netcore磊科无线路由器的管理页面(通常是192.168.1.1),则可能会遇到以下问题: IP地址冲突 网络设置错误 路由器故障 下面是一些可能有助于解决这些问题的方法: 方法一:检查IP地址冲突 如果您的计算机或其他设备使用与路由器相同的IP地址,则可能会导致无法访问路由器的管理页面。为了解决这个问题,您可以尝试更改计算机或其…

    C# 2023年5月17日
    00
  • 关于若干数据库数据插入性能的对比分析

    关于若干数据库数据插入性能的对比分析 介绍 在数据库应用中,数据插入操作是最频繁的操作之一。因此,对于数据库性能的优化,数据插入性能的分析非常重要。本文将介绍若干数据库数据插入性能对比分析的攻略。 步骤 1. 选择数据集 首先需要选择一个数据集。数据集的大小和内容对于数据插入性能对比测试的结果会有很大的影响。因此,在选择数据集时应该在考虑数据大小、数据类型、…

    C# 2023年5月31日
    00
  • c#快速写本地日志方法

    下面我就为你详细讲解“c#快速写本地日志方法”的完整攻略。 1. 确定需求及文件格式 第一步是确定你的需求及文件格式。一般来说,我们需要记录的日志信息包括时间、级别、描述、来源等。在文件格式上,常见的有TXT、XML和JSON格式等。在这里,我们以TXT格式为例。 2. 创建日志文件 在创建日志文件之前,你需要确定日志文件的路径和名称。一般来说,我们可以把日…

    C# 2023年5月15日
    00
  • ASP.Net前台调用后台变量的方法

    要在 ASP.Net 前台页面中调用后台的变量,可以通过以下方法实现: 在后台代码中定义变量并使用public或protected关键字进行修饰。例如: //定义变量 protected string MyVariable; //给变量赋值 MyVariable = "Hello, World!"; 在前台页面中使用“<%=” 闭合…

    C# 2023年6月7日
    00
  • 解读在C#中winform程序响应键盘事件的详解

    当一个winform程序运行时,用户可能会进行键盘输入操作。C#提供了键盘事件处理,使得我们能够简单地响应这些事件。在本文中,我们将学习如何在C#中处理键盘事件。 键盘事件 在C#中处理键盘事件,需要使用WindowsForms库提供的KeyPress, KeyUp和KeyDown事件。这些事件都继承自Control.KeyPressEventHandler…

    C# 2023年6月6日
    00
  • C#读取系统字体颜色与大小的方法

    下面就来详细讲解一下“C#读取系统字体颜色与大小的方法”的攻略。这个过程我会分为两个步骤来讲解:第一步是读取系统字体的大小,第二步是读取系统字体的颜色。 读取系统字体大小的方法 要读取系统字体的大小,我们可以使用SystemFonts这个类,其包含了许多可以用来读取系统字体的相关信息的静态属性和静态方法。其中,SystemFonts.CaptionFontS…

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