說明
權限認證是確定使用者身份的過程,可確定使用者是否有存取資源的權力。
今天跟大家分享類似 JWT 這種基於 token 的驗證機制
基於 token 的驗證機制,它不需要在服務端去保留使用者的認證資訊或者會話資訊。這就意味著基於 token 認證機制的應用,不需要去考慮使用者在哪一台伺服器登入了,這就為應用的擴展提供了便利。
流程上是這樣的:
- 使用者使用使用者名稱密碼來請求伺服器
- 伺服器進行驗證使用者的資訊
- 伺服器通過驗證發送給使用者一個 token
- 客戶端儲存 token,並在每次請求時附送上這個 token 值
- 服務端驗證 token 值,並回傳資料
那我今天給大家手擼一個類似 Jwt 的權限認證
示範
新建一個授權篩選器繼承 IAuthorizationFilter
public class ApiAuthorize : IAuthorizationFilter
{}
新建一個需要應用授權的特性和允許未通過身份驗證也可以存取的特性
public class MyAuthentication:Attribute, IFilterMetadata
{
}
public class MyNoAuthentication : Attribute, IFilterMetadata
{
}
我們需要在我們的授權過濾器判斷請求頭是否帶有應用授權的特性和允許未通過身份驗證也可以存取的特性,如果有允許未通過身份驗證也可以存取的特性就直接進入下一個管道,如果帶有應用授權的特性則進行 token 判斷
public class ApiAuthorize : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.Filters.Contains(new MyNoAuthentication()))
{
return;
}
var authorize = context.HttpContext.Request.Headers["MyAuthentication"];
if (string.IsNullOrWhiteSpace(authorize))
{
context.Result = new JsonResult("請求 authorize 不能為空");
return;
}
if (!MemoryCacheHelper.Exists(authorize))
{
context.Result = new JsonResult("無效的授權資訊或授權資訊已過期");
return;
}
}
}
可能有的小夥伴發現了,那我們 Token 怎麼去存取呢,一般的方案是使用 Cache 來處理,這裡就不做過多討論了,有想了解的小夥伴可以看我上一篇文章!
CacheHelper 程式碼
public class MemoryCacheHelper
{
public static MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
/// <summary>
/// 驗證快取項是否存在
/// </summary>
/// <param name="key">快取 Key</param>
/// <returns></returns>
public static bool Exists(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return _cache.TryGetValue(key, out _);
}
/// <summary>
/// 取得快取
/// </summary>
/// <param name="key">快取 Key</param>
/// <returns></returns>
public static object Get(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (!Exists(key))
throw new ArgumentNullException(nameof(key));
return _cache.Get(key);
}
/// <summary>
/// 新增快取
/// </summary>
/// <param name="key">快取 Key</param>
/// <param name="value">快取 Value</param>
/// <param name="expiresSliding">滑動過期時長(如果在過期時間內有操作,則以當前時間點延長過期時間)</param>
/// <param name="expiressAbsoulte">絕對過期時長</param>
/// <returns></returns>
public static bool AddMemoryCache(string key, object value)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_cache.Set(key, value,
new MemoryCacheEntryOptions()
{
SlidingExpiration = new TimeSpan(0, 0, 10),
Priority = CacheItemPriority.NeverRemove,
AbsoluteExpiration = DateTime.Now.AddMinutes(1)
});
return Exists(key);
}
}
權限認證程式碼基本完成了,我們回到剛剛的流程
使用者使用使用者名稱密碼來請求伺服器,伺服器進行驗證使用者的資訊,伺服器通過驗證發送給使用者一個 token
對於一個商用軟體來說絕大多數介面都需要應用授權後才能使用,所以我們註冊到全域,在 StartUp 類裡面註冊
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(o=>
{
o.Filters.Add<ApiAuthorize>();
o.Filters.Add<MyAuthentication>();
});
}
Token 生成原理我這裡就不做過多解讀了,本範例使用 AES 加密生成 Token 在我們服務端的請求 token 介面加上允許未通過身份驗證也可以存取的特性,然後頒發一個 Token
[HttpGet("GetToken")]
[MyNoAuthentication]
public IActionResult GetToken(string UserCode)
{
string token= AESEncrypt.Encrypt(UserCode);
MemoryCacheHelper.AddMemoryCache(token, User);
eturn Ok(token);
}
使用 Postman 請求生成 token,如圖所示

然後我們在新增一個需要應用授權的介面,由於我們註冊了全域的應用授權特性就不需要在帶上該特性了
[HttpGet("GetUserInformation")]
public IActionResult GetUserInformation()
{
return Ok(new { Name="123",Age=18,Sex="性別"});
}
不帶 token 使用 postman 請求該介面,如圖所示

帶上 token 使用 postman 請求該介面,如圖所示

通過剛才的範例我們清楚了解了權限認證的過程,今天的介紹就到此結束了!
最後大家如果喜歡我的文章,還麻煩給個關注並點個讚,希望 net 生態圈越來越好!