從零開始Blazor Server(5)--許可權驗證

2022-08-02 12:05:52

之前我們一直使用的是微軟自帶的身份驗證方式,即使用[Authorize]標籤來做。

但是這種方式十分不靈活,微軟推薦的方式是加Policy,但是這種方式對我們來說還是不夠靈活。


所以本節我們用完全自己校驗的方式完成許可權驗證。

OnNavigateAsync介紹

在 App.razor 裡面的Router節點,微軟給了一個OnNavigateAsync方法,這個方法在每次路由跳轉的時候都會執行,所以我們可以把我們的許可權驗證搬到這裡來。

App.razor

首先,我們在Router節點上增加OnNavigateAsync

<Router AppAssembly="@typeof(App).Assembly" OnNavigateAsync="PermissionCheck">

這裡我們的方法叫做PermissionCheck


然後我們來看這個PermissionCheck方法。

    private void PermissionCheck(NavigationContext context)
    {
        var whiteList = Furion.App.Configuration["WhiteList"];
        if (whiteList != null && whiteList.Split(',').Contains(context.Path))
        {
            return;
        }

        var user = Furion.App.User;
        if (user == null)
        {
            NavigationManager.NavigateTo("/Login");
            return;
        }

        if (user.Identity?.IsAuthenticated != true)
        {
            NavigationManager.NavigateTo("/Login");
            return;
        }

        if (!int.TryParse(user.FindFirst(ClaimTypes.Role)?.Value, out var roleId))
        {
            NavigationManager.NavigateTo("/Login");
            return;
        }

        var permission = PermissionEntity
            .Where(x => x.Roles!.Any(y => y.Id == roleId) && x.Url == context.Path).First();

        if (permission == null)
        {
            NavigationManager.NavigateTo("/Login");
        }

    }

這裡我們需要把Login這個頁面拿出來,因為我們的Login頁面應該是一個白名單頁面,無需登入也可以存取,所以我在appsettings.json中增加了一項,為WhiteList,這裡面以,分隔,所有在這裡面的路徑都是白名單路徑,可以不用登入直接存取。

"WhiteList": "Login"

這裡注意,OnNavigateAsync給的Path是相對路徑,不帶最前面的/,所以我們的Login也不能有/

這裡判斷如果是白名單,則直接return,正常跳轉。

var user = Furion.App.User;
        if (user == null)
        {
            NavigationManager.NavigateTo("/Login");
            return;
        }

        if (user.Identity?.IsAuthenticated != true)
        {
            NavigationManager.NavigateTo("/Login");
            return;
        }

然後獲取我們的登入資訊,如果沒有登入,那麼直接跳轉到Login頁面。

if (!int.TryParse(user.FindFirst(ClaimTypes.Role)?.Value, out var roleId))
        {
            NavigationManager.NavigateTo("/Login");
            return;
        }

這裡獲取我們當時在LoginController裡的RoleId

這裡注意,我稍微改了一下,之前的文章裡我們這裡面放的是RoleName,本來是打算根據使用者再獲取許可權,但是後來想想有點麻煩,就稍微改動了一下,具體的可以看下新的原始碼。實戰中建議還是不要直接放RoleId進去,因為這個玩意在實戰中往往是一對多的。

var permission = PermissionEntity
            .Where(x => x.Roles!.Any(y => y.Id == roleId) && x.Url == context.Path).First();

        if (permission == null)
        {
            NavigationManager.NavigateTo("/Login");
        }

最後我們判斷一下資料庫裡這個角色有沒有這個路徑的許可權,如果沒有,我們就跳轉。

這樣我們就可以實現根據path來判斷許可權了。

這裡由於是教學類的,所以所有的判斷我都是直接從資料庫裡取得,正式使用的時候建議放到快取裡面,如果沒有頁面都走一次資料庫,那麼資料庫的壓力會非常大。

預設資料的路徑我稍微修改了一下,去掉了前面的/,這裡直接把資料庫給刪掉,然後重新執行就行了。

原始碼在github:https://github.com/j4587698/BlazorLearn,分支lesson5