ASP.NET基于JWT的Web API身份验证及跨域调用实践
本文将详细讲解 ASP.NET 基于 JWT 的 Web API 身份验证及跨域调用实践,帮助读者理解如何构建一个基于 JWT 的 API 并使用跨域调用这个 API。
什么是JWT
JWT (JSON Web Token)是一个开放标准(RFC 7519),用于在各方之间安全地传输信息。它可以通过数字签名验证消息的完整性,同时也可以使用加密方式保护消息的保密性,因此适用于身份验证和信息交换。
JWT 三部分
JWT 由三部分组成:Header、Payload 和 Signature。每个部分的内容都是根据 Base64Url 算法将一些 JSON 序列化后的数据编码而成。这三部分的具体内容如下:
Header
Header 包含了两个属性,分别为 alg
和 typ
,通常情况下 alg
的值为 HS256,表示使用 HS256 算法进行签名;typ
的值通常为 JWT,用于说明此为 JWT。
示例:
{
"alg": "HS256",
"typ": "JWT"
}
Payload
Payload(负载)部分是 JWT 的主体,包含了具体的信息。Payload 是由一些声明组成的,每个声明包含有关实体(一般是用户)及其元数据的信息。同样也根据 Base64Url 算法编码。
常见的声明有:
iss
(Issuer):JWT 的签发者。sub
(Subject):JWT 的主题。exp
(Expiration Time):JWT 的过期时间。nbf
(Not Before):在此时间之前,该 JWT 无法使用。iat
(Issued At):JWT 的签发时间。
示例:
{
"sub": "1234567890",
"name": "Alice",
"admin": true,
"exp": 1516239022
}
Signature
Signature 主要用于验证接收方是否能够信任该 JWT。Signature 是由 Header 和 Payload 使用相应的密钥签名后生成的,例如令牌生成密钥为 secret
,则用 HS256
算法生成 Signature 的过程如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
示例:
HMACSHA256(
eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkJpdGFfTWlsbHkiLCAiYWRtaW4iOiB0cnVlLCAiZXhwIjogMTUxNjIzOTAyMn0wXuzT4BPUVUGkrzWSzBx3jI3eaBcd7rxUVkcwk
,
secret)
JWT 特点
- JWT 可以被轻松地在 HTTP 和 HTML 环境中传输;
- 由于 JWT 能够自包含,使用它的应用可以避免查询已授权的数据库;
- 由于签名能够确保消息完整性,自包含的 JWT 可以安全地使用跨域脚本;
- 由于 JSON 是几乎所有编程语言中的第一公民,因此使用 JWT 消息非常适合跨语言的应用程序集成。
如何使用JWT
1. 生成JWT令牌
首先需要引入 System.IdentityModel.Tokens.Jwt
和 System.Security.Cryptography
两个命名空间的依赖。
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
生成 JWT 的过程需要以下步骤:
- 要创建 JWT,需要使用
JwtSecurityToken
类。这个类有许多属性可以用来设置 JWT 的声明(payload)。 - 对于加密(和访问 JWT payload)的密钥,需要使用
SymmetricSecurityKey
类,它可以使用任何长度的字节流。 - 创建 JWT 需要一个 JSON 转换器,可使用
JsonSerializer
类。
示例:
public string GenerateJwtToken(string username, int userId, string secret)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.NameIdentifier, userId.ToString())
}),
Expires = DateTime.Now.AddDays(7),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature),
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
2. 验证JWT令牌
首先需要引入 Microsoft.IdentityModel.Tokens
和 System.IdentityModel.Tokens.Jwt
两个命名空间的依赖。
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
JWT 是否有效可以通过以下几个步骤进行验证:
- 解密 JWT 令牌中的 Signature 部分;
- 使用 Header 和 Payload 中的数据进行签名;
- 比较本地签名与解密的 Signature 是否匹配。
示例:
public bool ValidateJwtToken(string token, string secret)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secret);
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);
return validatedToken != null;
}
3. 使用JWT实现身份验证
在 JWT 中发送身份验证信息是最常见的用例。Web 应用程序可以执行以下操作:
- 一个用户自行进行身份验证,并获得一个带有所需声明的 JWT 令牌;
- Web 应用程序存储公钥,每次收到 JWT 后进行验证。
在 Web API 的请求中,需要在 Headers 中加入 Authorization: Bearer <your_jwt_token>
作为身份验证信息。
示例:
[Authorize]
public class HomeController : Controller
{
public IActionResult Index()
{
return Ok();
}
}
4. 使用JWT实现跨域调用
基于 CORS 机制,跨域调用需要服务端设置 Access-Control-Allow-Origin,这个需要服务端配置。同时使用 JWT 时,前端需要在请求中添加 Authorization 的 Header,在后端通过 GetOwinContext().Authentication.User即可获得反序列化后的 ClaimsPrincipal 对象。
示例:
前端代码:
fetch('https://localhost:12345/api/values', {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer <your_jwt_token_here>'
}
}).then(response => {
console.log(response);
}).catch(error => {
console.log(error);
});
后端代码:
[Authorize]
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IActionResult Get()
{
var username = User.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
var userId = User.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
var result = new
{
username = username,
userId = userId
};
return Ok(result);
}
}
总结
在本文中,我们了解了 JWT 的概念以及其在身份验证和信息交换方面的优势。我们还讨论了如何使用 ASP.NET Core 在 Web API 中实现 JWT 身份验证,以及如何通过 JWT 实现跨域调用。希望本文对读者有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:asp.net基于JWT的web api身份验证及跨域调用实践 - Python技术站