net core手擼一個基於token的權限認證

net core手擼一個基於token的權限認證

權限認證是確定用戶身份的過程, 可確定用戶是否有訪問資源的權力。

最后更新 2022/7/9 下午9:18
黑哥聊dotNet
预计阅读 5 分钟
分类
.NET
标签
.NET C#

說明

權限認證是確定用戶身份的過程, 可確定用戶是否有訪問資源的權力。

今天給大家分享一下類似 jwt 這種基於 token 的鑒權機制

基於 token 的鑒權機制,它不需要在服務端去保留用戶的認證信息或者會話信息。這就意味著基於 token 認證機制的應用,不需要去考慮用戶在哪一台伺服器登錄了,這就為應用的擴展提供了便利。

流程上是這樣的:

  1. 用戶使用用戶名密碼來請求伺服器
  2. 伺服器進行驗證用戶的信息
  3. 伺服器通過驗證發送給用戶一個 token
  4. 客戶端存儲 token,並在每次請求時附送上這個 token 值
  5. 服務端驗證 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 生態圈越來越好!

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2026/2/7

aot使用經驗總結

從項目創建伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 aot 發布測試。

继续阅读