之前我們一直使用的是微軟自帶的身份驗證方式,即使用[Authorize]
標籤來做。
但是這種方式十分不靈活,微軟推薦的方式是加Policy
,但是這種方式對我們來說還是不夠靈活。
所以本節我們用完全自己校驗的方式完成許可權驗證。
在 App.razor 裡面的Router
節點,微軟給了一個OnNavigateAsync
方法,這個方法在每次路由跳轉的時候都會執行,所以我們可以把我們的許可權驗證搬到這裡來。
首先,我們在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