什么是JWT:https://www.cnblogs.com/yan7/p/7857833.html
在前后端分離開發中會需要進行用戶驗證,本篇博客介紹如何在ASP.NET Core WebApi中使用JWT進行用戶認證。
本篇博客延續上一篇博客 https://www.cnblogs.com/gygg/p/12849641.html 配置swagger驗證功能
開發工具:Visual Studio2019
目標框架:.NET Core 3.1
一、啟用swagger驗證功能
1.1、AddSwaggerGen()方法中啟用swagger驗證功能,添加全局安全條件,自定義Heard Token
services.AddSwaggerGen(c =>
{
//啟用swagger驗證功能
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Description = "在下框中輸入請求頭中需要添加Jwt授權Token:Bearer Token",
Name = "Authorization",//jwt默認的參數名稱
In = ParameterLocation.Header,//jwt默認存放authorization信息的位置(請求頭中)
Type = SecuritySchemeType.ApiKey,
BearerFormat = "JWT",
Scheme = "Bearer"
});
//添加全局安全條件
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "Bearer"}
},new string[] { }
}
});
//顯示自定義的Heard Token
c.OperationFilter<AuthTokenHeaderParameter>();
});
1.2、添加 AuthTokenHeaderParameter 類,顯示自定義的Heard Token
public class AuthTokenHeaderParameter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Parameters = operation.Parameters ?? new List<OpenApiParameter>();
var isAuthor = operation != null && context != null;
if (isAuthor)
{
//in query header
operation.Parameters.Add(new OpenApiParameter()
{
Name = "Authorization",
Description = "身份驗證",
Required = false,
In = ParameterLocation.Header
});
}
if (!context.ApiDescription.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase) &&
!context.ApiDescription.HttpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase))
{
return;
}
}
}
啟動項目,效果圖如下

2、注冊JWT
2.1、添加 JWTTokenOptions 類
public class JWTTokenOptions
{
/// <summary>
/// 訂閱者
/// </summary>
public string Audience { get; set; }
/// <summary>
/// 發起人
/// </summary>
public string Issuer { get; set; }
/// <summary>
/// 過期時間 單位秒
/// </summary>
public long Expire { get; set; }
/// <summary>
/// 秘鑰
/// </summary>
public string Secret { get; set; }
}
2.2、在 appsettings.json 中配置JWTToken
"JWTToken": {
"Expire": 3600, //token過期時間 單位s
"Audience": "www.baidu.com", //訂閱者
"Issuer": "baidu", //發起人
"Secret": "************************" //秘鑰
}
2.3、在 startup 類的 ConfigureServices 方法中注冊 jwt
#region 注冊jwt
JWTTokenOptions JWTTokenOptions = new JWTTokenOptions();
//獲取appsettings的內容
services.Configure<JWTTokenOptions>(this.Configuration.GetSection("JWTToken"));
//將給定的對象實例綁定到指定的配置節
Configuration.Bind("JWTToken", JWTTokenOptions);
//注冊到Ioc容器
services.AddSingleton(JWTTokenOptions);
//添加驗證服務
services.AddAuthentication(option =>
{
//默認身份驗證模式
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//默認方案
option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(option =>
{
//設置元數據地址或權限是否需要HTTP
option.RequireHttpsMetadata = false;
option.SaveToken = true;
//令牌驗證參數
option.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//獲取或設置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用於簽名驗證。
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.
GetBytes(JWTTokenOptions.Secret)),
//獲取或設置一個System.String,它表示將使用的有效發行者檢查代幣的發行者。
ValidIssuer = JWTTokenOptions.Issuer,
//獲取或設置一個字符串,該字符串表示將用於檢查的有效受眾反對令牌的觀眾。
ValidAudience = JWTTokenOptions.Audience,
//是否驗證發起人
ValidateIssuer = false,
//是否驗證訂閱者
ValidateAudience = false,
////允許的服務器時間偏移量
ClockSkew = TimeSpan.Zero,
////是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比
ValidateLifetime = true
};
//如果jwt過期,在返回的header中加入Token-Expired字段為true,前端在獲取返回header時判斷
option.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
#endregion
2.4、在 startup 類的 Configure 方法中添加認證
app.UseAuthentication(); //添加認證 app.UseAuthorization(); //添加授權(.netCore 3.x中使用)
3、生成JWT
3.1、添加 TokenResult 類
public class TokenResult
{
/// <summary>
/// token字符串
/// </summary>
public string Access_token { get; set; }
/// <summary>
/// 過期時間
/// </summary>
public long Expires_in { get; set; }
}
3.2、添加 JwtTokenHelper 類
public class JwtTokenHelper
{
public JwtTokenHelper()
{
}
public TokenResult AuthorizeToken(int memberId, JWTTokenOptions _tokenOptions)
{
//基於聲明的認證
var claims = new[]
{
new Claim(ClaimTypes.Name,memberId.ToString()),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())//jwt的唯一標識
};
//秘鑰 轉化成UTF8編碼的字節數組
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenOptions.Secret));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);//資格證書 秘鑰加密
var jwtToken = new JwtSecurityToken(_tokenOptions.Issuer, _tokenOptions.Audience, claims,//發起人 訂閱者
expires: DateTime.Now.AddSeconds(_tokenOptions.Expire),//過期時間
signingCredentials: credentials);//秘鑰
var securityToken = new JwtSecurityTokenHandler().WriteToken(jwtToken);//序列化jwt格式
//生成令牌字符串
return new TokenResult()
{
Access_token = "Bearer " + securityToken,
Expires_in = _tokenOptions.Expire
};
}
}
3.3、添加生成 JWT 方法
[ApiController]
[Route("api/[controller]/[action]")]
public class HomeController : Controller
{
private readonly JWTTokenOptions _tokenOptions;
public HomeController(JWTTokenOptions tokenOptions)
{
_tokenOptions = tokenOptions;
}
/// <summary>
/// 生成jwt
/// </summary>
/// <returns></returns>
[HttpPost]
public TokenResult GenerateJwt()
{
var token = new JwtTokenHelper().AuthorizeToken(123456, _tokenOptions);
return token;
}
}
執行 GenerateJwt 方法,生成 jwt

在需要認證的 Controller 中添加 [Authorize] 特性

若未進行jwt認證,則報錯401

若進行了jwt 認證,則正常返回接口
End!
