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。
步骤:
- 在 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();
}
}
- 生成和发送 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技术站