身份驗證和授權是每一個后端服務必不可少的,可以實現對非法請求進行攔截,能夠有效保護數據的安全性。
JSON Web Token(JWT)是一項開放標準(RFC 7519),它定義了一種緊湊且自包含的方法,用于以 JSON 對象的形式在各方之間安全地傳遞信息。這些信息經過數字簽名,因此可以被驗證和信任。
JWT官網文檔:JSON Web Token Introduction - jwt.io
一、配置身份驗證和授權
1、添加身份驗證和JWT授權庫
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearerdotnet add package Microsoft.IdentityModel.Tokens
2、添加JWT配置信息到appsettings.json文件中
"JwtTokenConfig": {"Secret": "T#cx^Q$qsd8UrJMnY1(Vz$iie~lA3jgB96drYoPP4IDOffds&Qrw6GG+HClJteU#$)^JzMN_it#o*WE+*qVhE(_Ryy_t)","Issuer": "http://www.my.com/","Audience": "http://www.my.com/","AccessTokenExpiration": 240
}
3、創建JwtTokenConfig信息類
public class JwtTokenConfig
{public string Secret { get; set; } = string.Empty;public string Issuer { get; set; } = string.Empty;public string Audience { get; set; } = string.Empty;public int AccessTokenExpiration { get; set; }
}
4、啟用身份驗證和JWT授權服務
var builder = WebApplication.CreateBuilder(args);JwtTokenConfig? jwtTokenConfig = builder.Configuration.GetSection("JwtTokenConfig").Get<JwtTokenConfig>();
if (jwtTokenConfig != null)
{builder.Services.AddSingleton(jwtTokenConfig);builder.Services.AddAuthentication(x =>{x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(x =>{x.RequireHttpsMetadata = true;x.SaveToken = true;x.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,ValidIssuer = jwtTokenConfig.Issuer,ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtTokenConfig.Secret)),ValidAudience = jwtTokenConfig.Audience,ValidateAudience = true,ValidateLifetime = true,ClockSkew = TimeSpan.FromMinutes(1)};});
}var app = builder.Build();
5、顯示注冊身份驗證和授權
var app = builder.Build();app.UseCors();
app.UseAuthentication();
app.UseAuthorization();app.MapGet("/", () => "Hello World!");
app.Run();
注:身份驗證中間件是在 CORS 中間件運行后運行的,所以需要顯示注冊身份驗證和授權
6、在控制器基類中添加授權特性,對所有控制器施加授權驗證
[Route("api/[controller]/[action]")]
[ApiController]
[Authorize]
public abstract class BaseController : ControllerBase
{}
二、生成JWT授權碼
1、添加身份驗證和JWT授權庫
dotnet add package System.IdentityModel.Tokens.Jwtdotnet add package Microsoft.IdentityModel.Tokens
2、創建JWT授權服務接口
public interface IJwtAuthService
{string GenerateJwtToken(Claim[] claims);
}
3、創建JWT授權服務業務邏輯
public class JwtAuthService : IJwtAuthService
{private readonly JwtTokenConfig _jwtTokenConfig;public JwtAuthService(JwtTokenConfig jwtTokenConfig){_jwtTokenConfig = jwtTokenConfig;}public string GenerateJwtToken(Claim[] claims){bool shouldAddAudienceClaim = string.IsNullOrWhiteSpace(claims?.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Aud)?.Value);JwtSecurityToken jwtToken = new(_jwtTokenConfig.Issuer,shouldAddAudienceClaim ? _jwtTokenConfig.Audience : string.Empty,claims,expires: DateTime.Now.AddMinutes(_jwtTokenConfig.AccessTokenExpiration),signingCredentials: new SigningCredentials(new SymmetricSecurityKey(_secret), SecurityAlgorithms.HmacSha256Signature));return new JwtSecurityTokenHandler().WriteToken(jwtToken);}
}
4、注冊JWT授權服務
var builder = WebApplication.CreateBuilder(args);builder.Services.AddSingleton<IJwtAuthService, JwtAuthService>();var app = builder.Build();
5、在授權控制器中使用JWT服務,生成Token
public class AuthController : BaseController
{private readonly IJwtAuthService _authService;public AuthController(IAuthService authService){_authService = authService;}[AllowAnonymous][HttpPost]public IActionResult Login([FromBody] LoginRequest request){// 1. 驗證用戶名密碼(偽代碼)if (!IsValidUser(request.User, request.Password))return Unauthorized();// 2. 創建JWT聲明(偽代碼)string roleName = "User";Claim[] claims =[new Claim(ClaimTypes.NameIdentifier, user),new Claim(ClaimTypes.Role, roleName)];// 3. 生成 JWT Tokenvar token = _authService.GenerateJwtToken(claims);// 4. 返回 Tokenreturn Ok(new { Token = token });}private bool IsValidUser(string user, string password){// 實際應該查數據庫(偽代碼)return user == "admin" && password == "123456";}
}
注:使用ClaimTypes.NameIdentifier來聲明用戶標識,可以在集成SignalR時使SignalR很容易獲取到用戶標識并進行消息發送,因為SignalR默認獲取的用戶標識就是ClaimTypes.NameIdentifier