說明
權限認證是確定用戶身份的過程, 可確定用戶是否有訪問資源的權力。
今天給大家分享一下類似 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 生態圈越來越好!