天天看點

Blazor頁面元素授權——AuthorizeView 元件的使用Blazor頁面元素授權——AuthorizeView 元件的使用基于角色的授權方式

Blazor頁面元素授權——AuthorizeView 元件的使用

上篇部落格我們說到了blazor的身份認證的實作,對于AuthorizeView 元件來說,可以通過級聯參數來擷取包含了使用者資訊的AuthenticationState對象。

請注意,你需要引用Microsoft.AspNetCore.Components.Authorization Nuget包,并且在啟動類中添加服務

Services.AddAuthorizationCore();

使用CascadingAuthenticationState元件包裹App.razor中的代碼:

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>
           

如果未指定授權條件,則 AuthorizeView 使用預設政策:

  • 将經過身份驗證(已登入)的使用者視為已授權。
  • 将未經過身份驗證(已登出)的使用者視為未授權。

基于角色的授權方式

角色的擷取方式是多樣的,可以來自項目本身,也可以來自外部的權限系統。總之,你需要清楚角色對應的權限本身範圍,比如控制了哪些頁面可以通路,哪些按鈕是可見的。

請記住,僅在用戶端進行權限控制并不是安全的。

在AuthorizeView元件中包裹需要驗證角色才可以檢視的元件

<AuthorizeView Roles="admin">
    <p>You can only see this if you're an admin or superuser.</p>
</AuthorizeView>
           

我個人是将認證與授權作為兩個服務。授權服務根據系統碼以及子產品Id,調用權限管理系統接口,權限系統會根據目前使用者來傳回權限樹,而我拿到權限樹之後,會将其中的按鈕或是頁面的權限辨別作為Roles,寫入AuthenticationState當中,使用上面例子的方式,控制頁面元素的展示。

下面附上完整的授權服務代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using ClientSideTemplate.Client.Foundation.Authentication.Model;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Http;
using Newtonsoft.Json;

namespace ClientSideTemplate.Client.Foundation.Authentication
{
    public class AuthorizedService
    {
        private readonly IServiceClient _serviceClient;
        private readonly AuthorizedOption _authorizedOption;

        public AuthorizedService(IServiceClient serviceClient, AuthorizedOption authorizedOption)
        {
            _serviceClient = serviceClient;
            _authorizedOption = authorizedOption;
        }

        public async Task AuthorizedAsync(AuthenticationState state)
        {
#if DEBUG
            var identity = new ClaimsIdentity(_authorizedOption.ModuleIds.Select(x => new Claim(ClaimTypes.Role, x)));
            state.User.AddIdentity(identity);
#else
            foreach (var moduleId in _authorizedOption.ModuleIds)
            {
                var userInfo = await GetUserInfo(_authorizedOption.SystemCode, moduleId);
                var identity = new ClaimsIdentity(userInfo.PrivilegeTree.Select(x => new Claim(ClaimTypes.Role, x.ModuleId)));
                state.User.AddIdentity(identity);
            }
#endif
        }

        private async Task<UserInfo> GetUserInfo(string systemCode, string moduleId)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, $"/login/Auth/UserInfo?systemCode={systemCode}&moduleId={moduleId}");
            request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);

            var response = await _serviceClient.SendAsync(request);
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
#if !DEBUG
                SignIn();
#endif
            }

            var content = await response.Content.ReadAsStringAsync();
            if (string.IsNullOrWhiteSpace(content))
            {
                return new UserInfo();
            }

            return JsonConvert.DeserializeObject<ApiResult<UserInfo>>(content).Result;
        }
    }
}

           

另外,如果你想在代碼中擷取AuthenticationState,請以級聯參數的形式:

[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
           

繼續閱讀