C#中運(yùn)用JWT用戶認(rèn)證的實(shí)現(xiàn)
一、JWT概述
JSON Web Token(JWT)是一種輕量級(jí)的身份認(rèn)證機(jī)制,廣泛應(yīng)用于分布式系統(tǒng)中的用戶認(rèn)證。它通過緊湊的JSON格式存儲(chǔ)用戶身份信息,并使用數(shù)字簽名確保信息的完整性和真實(shí)性。與傳統(tǒng)的基于Session的認(rèn)證相比,JWT具有無狀態(tài)、可擴(kuò)展、跨平臺(tái)等優(yōu)勢(shì),特別適合于微服務(wù)架構(gòu)和前后端分離的應(yīng)用場(chǎng)景。
JWT的核心優(yōu)勢(shì)在于:
- 無狀態(tài):服務(wù)器不需要存儲(chǔ)會(huì)話信息,減輕服務(wù)器負(fù)擔(dān)
- 跨平臺(tái):基于標(biāo)準(zhǔn)JSON格式,可在不同語言和平臺(tái)間傳遞
- 自包含:令牌包含所有必要的用戶信息,減少數(shù)據(jù)庫(kù)查詢
- 可擴(kuò)展:支持自定義聲明,滿足不同業(yè)務(wù)需求
- 安全性:通過數(shù)字簽名確保信息不被篡改
二、JWT工作原理
JWT認(rèn)證的核心流程如下:
- 用戶登錄:用戶提供用戶名和密碼進(jìn)行登錄
- 生成Token:服務(wù)器驗(yàn)證成功后,生成包含用戶身份信息的JWT令牌
- 返回Token:服務(wù)器將JWT令牌返回給客戶端
- 存儲(chǔ)Token:客戶端存儲(chǔ)JWT令牌(通常存儲(chǔ)在localStorage或Cookie中)
- 請(qǐng)求攜帶Token:客戶端后續(xù)請(qǐng)求時(shí),在HTTP頭部攜帶JWT令牌
- 驗(yàn)證Token:服務(wù)器驗(yàn)證JWT令牌的有效性(簽名驗(yàn)證、過期時(shí)間檢查等)
- 處理請(qǐng)求:驗(yàn)證通過后,服務(wù)器處理請(qǐng)求并返回結(jié)果
JWT認(rèn)證流程圖
+----------+ 登錄請(qǐng)求 +----------+
| | --------------> | |
| 客戶端 | | 服務(wù)器 |
| | <-------------- | |
+----------+ 返回JWT令牌 +----------+
| |
| 攜帶JWT令牌的請(qǐng)求 |
| -----------------------------> |
| |
| <----------------------------- |
| 處理后的響應(yīng) |
v v三、JWT結(jié)構(gòu)組成
JWT令牌由三部分組成,用小數(shù)點(diǎn)(.)分隔,格式為Header.Payload.Signature:
1. Header(頭部)
Header部分包含令牌類型(typ)和加密算法(alg),通常如下:
{
"alg": "HS256",
"typ": "JWT"
}其中,alg表示使用的加密算法(如HS256、RS256等),typ表示令牌類型。
2. Payload(載荷)
Payload部分包含用戶身份信息和其他元數(shù)據(jù),分為標(biāo)準(zhǔn)聲明和自定義聲明:
標(biāo)準(zhǔn)聲明:
- iss:令牌頒發(fā)者
- sub:令牌主題(通常是用戶ID)
- aud:令牌受眾
- exp:令牌過期時(shí)間
- iat:令牌頒發(fā)時(shí)間
- nbf:令牌生效時(shí)間
- jti:令牌唯一標(biāo)識(shí)符
自定義聲明:根據(jù)業(yè)務(wù)需求定義的字段,如用戶角色、權(quán)限等。
示例:
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"exp": 1678900000
}3. Signature(簽名)
Signature部分是對(duì)Header和Payload的簽名,用于驗(yàn)證令牌的完整性和真實(shí)性。服務(wù)器使用Header中指定的算法,結(jié)合密鑰對(duì)Header和Payload進(jìn)行簽名:
PlainText HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secretKey )
四、C#中實(shí)現(xiàn)JWT認(rèn)證
1. 安裝必要的包
在C#項(xiàng)目中,我們需要安裝以下NuGet包:
- System.IdentityModel.Tokens.Jwt:用于生成和驗(yàn)證JWT令牌
- Microsoft.AspNetCore.Authentication.JwtBearer:提供JWT身份驗(yàn)證中間件
Install-Package System.IdentityModel.Tokens.Jwt Install-Package Microsoft.AspNetCore. Authentication.JwtBearer
2. 配置JWT認(rèn)證服務(wù)
在Program.cs文件中,添加JWT認(rèn)證服務(wù)配置:
Program.cs
using Microsoft.AspNetCore.Authentication.
JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
?
var builder = WebApplication.CreateBuilder(args);
?
// 添加JWT認(rèn)證服務(wù)
builder.Services.AddAuthentication
(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new
TokenValidationParameters
{
ValidateIssuer = true, // 驗(yàn)證頒發(fā)者
ValidateAudience = true, // 驗(yàn)證受眾
ValidateLifetime = true, // 驗(yàn)證過期時(shí)
間
ValidateIssuerSigningKey = true, // 驗(yàn)
證簽名密鑰
ValidIssuer = builder.Configuration
["Jwt:Issuer"], // 頒發(fā)者
ValidAudience = builder.Configuration
["Jwt:Audience"], // 受眾
IssuerSigningKey = new
SymmetricSecurityKey(Encoding.UTF8.
GetBytes(builder.Configuration
["Jwt:SecretKey"])) // 簽名密鑰
};
});
?
// 添加授權(quán)服務(wù)
builder.Services.AddAuthorization();
?
var app = builder.Build();
?
// 使用認(rèn)證和授權(quán)中間件
app.UseAuthentication();
app.UseAuthorization();
?
app.MapControllers();
app.Run();3. 配置appsettings.json
在appsettings.json文件中添加JWT相關(guān)配置:
appsettings.json
應(yīng)用
{
"Jwt": {
"Issuer": "YourIssuer",
"Audience": "YourAudience",
"SecretKey":
"YourSecretKeyHereShouldBeLongEnough"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}4. 生成JWT令牌
創(chuàng)建一個(gè)AuthController,實(shí)現(xiàn)用戶登錄和生成JWT令牌的功能:
AuthController.cs
?
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
?
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IConfiguration
_configuration;
?
public AuthController(IConfiguration
configuration)
{
_configuration = configuration;
}
?
[HttpPost("login")]
public IActionResult Login([FromBody]
LoginRequest request)
{
// 驗(yàn)證用戶憑據(jù)(實(shí)際應(yīng)用中應(yīng)查詢數(shù)據(jù)庫(kù))
if (request.Username == "admin" &&
request.Password == "password")
{
// 創(chuàng)建用戶聲明
var claims = new[]
{
new Claim(ClaimTypes.Name,
request.Username),
new Claim(ClaimTypes.Role,
"admin"),
new Claim(JwtRegisteredClaimNames.
Sub, "1234567890"),
new Claim(JwtRegisteredClaimNames.
Jti, Guid.NewGuid().ToString())
};
?
// 生成對(duì)稱安全密鑰
var key = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(_configuration
["Jwt:SecretKey"]));
?
// 生成簽名憑據(jù)
var creds = new SigningCredentials
(key, SecurityAlgorithms.HmacSha256);
?
// 創(chuàng)建JWT令牌
var token = new JwtSecurityToken(
issuer: _configuration
["Jwt:Issuer"],
audience: _configuration
["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes
(30),
signingCredentials: creds);
?
// 返回JWT令牌
return Ok(new
{
token = new
JwtSecurityTokenHandler().
WriteToken(token),
expiration = token.ValidTo
});
}
?
return Unauthorized();
}
}
?
public class LoginRequest
{
public string Username { get; set; }
public string Password { get; set; }
}5. 保護(hù)API端點(diǎn)
使用[Authorize]屬性保護(hù)API端點(diǎn),只有攜帶有效JWT令牌的請(qǐng)求才能訪問:
ValuesController.cs
?
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
?
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class ValuesController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok(new string[] { "value1",
"value2" });
}
?
[HttpGet("{id}")]
[Authorize(Roles = "admin")]
public IActionResult Get(int id)
{
return Ok($"value {id}");
}
}五、JWT認(rèn)證的注意事項(xiàng)
- 密鑰安全:確保JWT密鑰安全存儲(chǔ),避免硬編碼在代碼中
- 令牌過期時(shí)間:設(shè)置合理的令牌過期時(shí)間,平衡安全性和用戶體驗(yàn)
- HTTPS傳輸:使用HTTPS協(xié)議傳輸JWT令牌,防止中間人攻擊
- 令牌刷新機(jī)制:實(shí)現(xiàn)令牌刷新機(jī)制,避免用戶頻繁登錄
- 敏感信息:不要在JWT中存儲(chǔ)敏感信息,如密碼等
- 權(quán)限控制:結(jié)合角色和權(quán)限聲明,實(shí)現(xiàn)細(xì)粒度的訪問控制
到此這篇關(guān)于C#中運(yùn)用JWT用戶認(rèn)證的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C# JWT用戶認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# 實(shí)現(xiàn)WebSocket服務(wù)端教程
這篇文章主要介紹了C# 實(shí)現(xiàn)WebSocket服務(wù)端教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
C#中的Task.WhenAll和Task.WhenAny方法介紹
這篇文章介紹了C#中的Task.WhenAll和Task.WhenAny方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
Unity實(shí)現(xiàn)植物識(shí)別示例詳解
這篇文章主要介紹了如何通過Unity接入百度AI實(shí)現(xiàn)植物識(shí)別,接口返回植物的名稱,并支持獲取識(shí)別結(jié)果對(duì)應(yīng)的百科信息。感興趣的可以了解一下2022-01-01
C# Winform實(shí)現(xiàn)導(dǎo)入和導(dǎo)出Excel文件
這篇文章主要為大家詳細(xì)介紹了C# Winform實(shí)現(xiàn)導(dǎo)入和導(dǎo)出Excel文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12

