上篇講到Blazor WebAssembly前端實現了簡單的登錄授權驗證,但是無法結合我們系統后端配置的權限做相應的策略授權。本篇就講一下如何自定義實現基於策略的授權。
要用兩個步驟來實現
1、后端把權限信息讀取到前端緩存。
后端實現一個接口,以下是代碼:
/// <summary>
/// 是否有權限
/// </summary>
/// <param name="policy"></param>
/// <returns></returns>
public async Task<List<PermissionGrantedDto>> AuthorizeAsync(List<string> policys)
{
List<PermissionGrantedDto> list = new List<PermissionGrantedDto>();
foreach (string policy in policys)
{
bool isGranted= (await AuthorizationService.AuthorizeAsync(policy)).Succeeded;
PermissionGrantedDto permissionGrantedDto = new PermissionGrantedDto();
permissionGrantedDto.PermissionName = policy;
permissionGrantedDto.IsGranted = isGranted;
list.Add(permissionGrantedDto);
}
return list;
}
通過這個接口能實現前端把所有權限名稱傳到后端來獲取到是否有授權信息返回給前端。
前端就要實現以下幾個地方:
1、存儲權限名稱的
public class PermissionData
{
public const string CategoryManagement = "Category_Management";
public const string CategoryManagementCreate = "Category_Management_Create";
public const string CategoryManagementEdit = "Category_Management_Edit";
public const string CategoryManagementDelete = "Category_Management_Delete";
}
2、緩存權限授權信息的
public class PermissionGrantedCache
{
/// <summary>
/// 權限名
/// </summary>
public string PermissionName { get; set; }
/// <summary>
/// 是否有權限
/// </summary>
public bool IsGranted { get; set; }
}
以上就能實現了前端把權限名稱傳到后端獲取授權信息,然后緩存到前端。
接下來就是實現如何自定義實現權限是授權判斷了
首先繼承DefaultAuthorizationPolicyProvider實現
public class CustomAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider
{
private readonly AuthorizationOptions _options;
public CustomAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options): base(options)
{
_options = options.Value;
}
public override async Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
var policy = await base.GetPolicyAsync(policyName);
if (policy != null)
{
return policy;
}
var policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
policyBuilder.Requirements.Add(new PermissionRequirement(policyName));
return policyBuilder.Build();
}
}
public class PermissionRequirement : IAuthorizationRequirement
{
public string PermissionName { get; }
public PermissionRequirement(string permissionName)
{
PermissionName = permissionName;
}
}
然后繼承AuthorizationHandler實現
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>
{
private static List<PermissionGrantedCache> _permissionGrantedCaches;
private readonly TokenHttpClient _tokenHttpClient;
public PermissionRequirementHandler(TokenHttpClient tokenHttpClient)
{
_tokenHttpClient = tokenHttpClient;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
if ((await PermissionGranted(requirement.PermissionName)))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
//return Task.CompletedTask;
}
protected async Task<bool> PermissionGranted(string permissionName)
{
_permissionGrantedCaches= _permissionGrantedCaches ?? new List<PermissionGrantedCache>();
var grantedCache = _permissionGrantedCaches.FirstOrDefault(p => p.PermissionName == permissionName);
if (grantedCache != null)
{
return grantedCache.IsGranted;
}
else
{
_permissionGrantedCaches.Clear();
//獲取所有權限
FieldInfo[] fis = typeof(PermissionData).GetFields();
List<string> pinfoList = new List<string>();
foreach (FieldInfo pinfo in fis)
{
pinfoList.Add(pinfo.GetRawConstantValue().ToString());
}
var response = await _tokenHttpClient.PostAsJsonWithTokenAsync($"/api/Test/authorization/authorize", pinfoList);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
_permissionGrantedCaches.AddRange(JsonConvert.DeserializeObject<List<PermissionGrantedCache>>(content));
var grantedCacheNew = _permissionGrantedCaches.FirstOrDefault(p => p.PermissionName == permissionName);
if (grantedCacheNew != null)
{
return grantedCacheNew.IsGranted;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
}
最后在program.cs里注入
builder.Services.AddScoped<CustomAuthorizationPolicyProvider>();
builder.Services.AddScoped<IAuthorizationPolicyProvider>(s => s.GetRequiredService<CustomAuthorizationPolicyProvider>());
builder.Services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>();
builder.Services.AddSingleton<PermissionData, PermissionData>();
builder.Services.AddSingleton<PermissionGrantedCache, PermissionGrantedCache>();
怎么使用呢?看使用辦法:
@page "/commodities/categorymanage"
@attribute [Authorize(PermissionData.CategoryManagement)]
<h1>類別設置</h1>
@code {
}
這樣就實現了自定義的權限授權了。
