基於Angular和AspNetCore的權限管理系統(三)登錄流程

認證方式

aspnetcore的基本認證方式是:攜帶着認證信息的數據進入應用程序,經過認證中間件。如果驗證通過,會把信息鍾攜帶的用戶的claim集中生成ClaimsPrincipal,然後就可以在程序中訪問用戶信息了。

在本系統中使用了JWT的方式進行認證,關於jwt可以看這裏。aspnetcore使用jwt也很簡單,官方文檔有很直接的例子。在系統中實現了這樣幾項和jwt相關的功能。

  • jwt是有時效性的,爲了防止token過期影響用戶操作。在客戶端創建了http請求的管道,在進行任何服務器請求前先對token的expire進行判斷是否過期。如果將要過期或已經過期,就去請求後臺的刷新token接口。後臺接口會讀取舊token,刷新服務是允許token過期一小段時間的,驗證通過則會根據舊token信息派發新token。用戶取得新token後,纔會繼續後面的處理。這樣就完成了在用戶無感知情況下保持登錄狀態。
  • 爲了防止token被濫用,在服務端生成token的同時會以用戶名爲key,token數據爲value記錄在緩存中,相當於白名單。如果賬號在別地登錄,或者管理員修改用戶信息,都會導致token緩存發生變化。在認證過程中,就會失敗並返回錯誤信息。這時客戶端可以根據錯誤信息,強制用戶註銷。jwt本身的認證方式和白名單並不衝突,因爲白名單不僅可以記錄token本身,還可以記錄ip等信息來防止異地訪問。下面是白名單驗證的代碼:
services.AddAuthentication(ops =>
            {
                ops.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                ops.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(ops =>
            {
                ops.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = option.Issuer,
                    ValidateIssuer = true,
                    ValidAudience = option.Audience,
                    ValidateAudience = true,
                    IssuerSigningKey = option.SecurityKey,
                    ValidateIssuerSigningKey = true,
                    ValidateLifetime = true,
                };

                ops.Events = new JwtBearerEvents()
                {
                    OnMessageReceived = context => { return Task.CompletedTask; },
                    OnTokenValidated = context =>
                     {
                         var memoryCache = context.HttpContext.RequestServices.GetRequiredService<IMemoryCache>();

                         var userName = context.Principal.GetUserName();
                         var exist = memoryCache.TryGetValue(userName, out string token);
                         if (exist)
                         {
                             var bearerToken = context.Request.Headers["Authorization"].ToString();
                             if (!bearerToken.Contains(token))
                             {
                                 context.Fail("TokenNoExist");
                             }
                         }
                         else
                         {
                             context.Fail("TokenNoExist");
                         }
                         return Task.CompletedTask;
                     },
                    OnChallenge = context =>
                    {
                        if (context.AuthenticateFailure.Message == "TokenNoExist")
                        {
                            context.HandleResponse();
                            context.Response.StatusCode = 470;
                        }
                        return Task.CompletedTask;
                    }

                };
            });

授權方式

在上邊的認證中獲取了用戶的信息,所以這裏就需要根據用戶的信息去給用戶進行授權。微軟提供了豐富的授權方式,我們的需求要做的是API的訪問授權,需要自定授權策略。

這裏的步驟就簡單了,我們先建立ApiAuthorizationHandler這個類,對請求進行處理判斷。首先我們獲取請求的api路徑和http方法。然後判斷此請求是否在用戶的角色中的元素的api的合集中,如果在說明用戶有權限訪問此處理,如果沒有則禁止授權。

然後將ApiAuthorizationRequirement和ApiAuthorizationHandler註冊到服務中。

            //【授權】
            services.AddAuthorization(options =>
            {
                options.AddPolicy("ApiPermission", policy => policy.Requirements.Add(new ApiAuthorizationRequirement()));
            });

            // 注入權限處理器
            services.AddTransient<IAuthorizationHandler, ApiAuthorizationHandler>();

最後一步,綁定控制器

    /// <summary>
    /// 授權訪問API控制器
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    [Authorize]
    [Authorize("ApiPermission")]
    public abstract class AuthorizeController : ControllerBase
    {
    }

然後所有需要進行認證和授權的控制器繼承此類就完成了。

授權方式

下邊說一下系統的登錄流程,畫了一個簡單的圖

在token中只保存了用戶名和角色等簡單的信息。頁面訪問的Identifycation和route是放在response中返回到web端,由web端自行處理。角色的api的訪問權限放在緩存中,授權時根據用戶的角色進行判斷。用戶的數據過濾器放在緩存中,數據的倉儲類實例化時會自動加載緩存中的過濾器。這樣就完成了整個的權限認證過程。

除了用戶名密碼登錄也可以任意更改成其他類型的登錄方式,譬如手機登錄,微信第三方登錄。所有登錄方式都需要去取得用戶數據,然後後面的流程就都一樣了。

總結

這三篇文章講了一下系統思路,可能有錯誤的地方。要是覺得有點幫助,可以star一下。有時間會繼續完善重構現在的功能,未來計劃添加更多模塊,做成一個大系統。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章