.NET Core如何全域性獲取使用者資訊?

Jeffcky發表於2021-07-06

前言

在增刪改查中的增和改操作中,我們經常需要更新資料流的建立人和修改人,無論我們專案是基於DDD,抑或是簡單僅有服務層,此時我們都需要獲取使用者資訊,那麼我們只能將使用者標識從控制器層層傳遞到服務或倉儲層?鑑於如上場景很常見,難道我們沒發覺這樣做很是繁瑣嗎?於是乎,我們想要解放生產力,下面我們們來聊聊我個人的想法

全域性獲取使用者資訊

既然是全域性獲取使用者資訊,難道是定義靜態變數?怎麼可能,當然是基於請求而獲取,基於靜態變數必然存在多個使用者請求覆蓋資訊的情況,那我們到底應該怎麼全域性獲取?首先我們想到的過濾器比如ActionFilter...等等,但要是我們需要進行非同步操作呢?貌似又不可行,根據我查詢官方文件,沒搞錯的話,應該是從1.0開始就給出了非同步過濾器,那就是IAsyncActionFilter,此方法不同於ActionFilter的是,它能夠處理非同步操作,同時它是在模型繫結完成之後執行,也就是隻有一個非同步方法

public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
    await next();
}

接下來我們定義全域性使用者會話類,如下:

public class Session
{
    /// <summary>
    /// 使用者id
    /// </summary>
    public string UserId { get; set; }
    /// <summary>
    /// 使用者名稱
    /// </summary>
    public string UserName { get; set; }
}

緊接著,比如專案我們使用JWT,則拿到宣告中使用者標識和使用者賬號,那麼我們接下來我們只需要實現上述非同步action過濾器介面即可,如下:

public class AsyncSessionFilter : IAsyncActionFilter
{
    private readonly Session _session;
 
    public AsyncSessionFilter(Session session)
    {
        _session = session;
    }
    
    public async Task OnActionExecutionAsync(
      ActionExecutingContext context,
      ActionExecutionDelegate next)
    {
        var user = context.HttpContext.User;

        _session.UserId = user.FindFirst(JwtRegisteredClaimNames.Sub)?.Value;

        _session.UserName = user.FindFirst(JwtRegisteredClaimNames.UniqueName)?.Value;

        await next();
    }
}

最後,則很簡單的進行上述介面實現和會話注入,如下:

//註冊使用者會話
services.AddScoped<Session>();
   
//註冊全域性過濾器   
services.AddControllers(options =>
{
   options.Filters.Add<AsyncSessionFilter>();
})

在實際使用中,我們只需要在倉儲或服務層建構函式使用Session,即可拿到使用者名稱和使用者id,從而最終解決對於新增和更改操作處理操作人資訊

總結

? 在.NET Core中藉助實現非同步IAsyncActionFilter介面而實現全域性獲取使用者資訊

相關文章