在 Blazor Wasm 中使用角色
Using roles in Blazor Wasm
我已经使用 Azure AD 单一原则设置了身份验证。使用应用程序角色进行授权。
API 是带有 swagger 客户端的 asp.net 核心 3.1。一切都经过测试,一切正常。
Blazor 客户端可以登录。但是 user.Identity 没有角色声明,因此 AuthorizeView 无法正常工作。
那我错过了什么?一个 nuget 包还是我必须将角色映射到自定义用户帐户?
这是我的具有 3 个角色的 jwt 令牌
{
"aud": "https://testacompany.onmicrosoft.com/customeredit-api",
"iss": "https://sts.windows.net/8506d453-347c-4239-adf7-602ca98f4853/",
"iat": 1614587145,
"nbf": 1614587145,
"exp": 1614591045,
"acr": "1",
"aio": "AUQAu/8TAAAAf2oBifx9vVtfPJXmlKP/MOzvpF3Flcnlt2BLFHe8B9K2NUFrQF4XP69vRu8voLMK5eo8zGgIl/aTdHOnrqmGaQ==",
"amr": [
"pwd"
],
"appid": "1a454d3f-329b-490d-b0fe-521bf6f61478",
"appidacr": "0",
"email": "xxx@acompany.dk",
"given_name": "Martin",
"idp": "https://sts.windows.net/3443ebe9-de49-471a-b7e5-9f9abfafac0c/",
"ipaddr": "131.165.55.123",
"name": "Martin Andersen",
"oid": "f121e73d-f5d8-436a-aef5-954cd286e80e",
"rh": "0.AAAAU9QGhXw0OUKt92AsqY9IUz9NRRqbMg1JsP5SG_b2FHiBAOY.",
"roles": [
"EditCustomer",
"EditAgreement",
"Reader"
],
"scp": "Api.Access",
"sub": "oxMQxcyNNgU-fZMto4xwOOwrI18mlUgM1GyyNhAFmDQ",
"tid": "8506d453-347c-4239-adf7-602ca98f4853",
"unique_name": "xxx@acompany.dk",
"uti": "K-zFcTY_mUG6RNzI-FdgAA",
"ver": "1.0"
}
在 Blazor 中 Program.cs
b.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>(options =>
{
options.UserOptions.RoleClaim = "role";
b.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://testacompany.onmicrosoft.com/customeredit-api/Api.Access");
}).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState,CustomUserAccount ,CustomUserFactory>();
b.Services.AddOptions();
b.Services.AddAuthorizationCore();
我还尝试创建 CustomUserFactory
public class CustomUserFactory : AccountClaimsPrincipalFactory<CustomUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
Console.WriteLine($"User IsAuthenticated: {user.Identity.IsAuthenticated}");
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims.Any())
{
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
if (rolesElem is JsonElement roles)
{
Console.WriteLine($"JsonElement: {rolesElem}");
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
Console.WriteLine($"role: {role.GetString()}");
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
Console.WriteLine($"roles: {roles.GetString()}");
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
}
}
}
return user;
}
}
但我想我需要解析原始 jwt 并将角色映射到我的用户。
那么如何访问 jwt 令牌?
此实施应该可以解决您的问题。我希望它包含在 .net 6+ 的未来模板中。
在 Blazor 中 Program.cs
builder.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>
(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://testacompany.onmicrosoft.com/customeredit-api/Api.Access");
options.UserOptions.RoleClaim = "role";
}).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomUserFactory>();
创建自定义用户工厂:
public class CustomUserFactory : AccountClaimsPrincipalFactory<CustomUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(CustomUserAccount account, RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity.IsAuthenticated)
{
var userIdentity = (ClaimsIdentity)initialUser.Identity;
if (account?.Roles?.Length > 0)
{
foreach (var role in account?.Roles)
{
userIdentity.AddClaim(new Claim("role", role));
}
}
if (account?.Groups?.Length > 0)
{
foreach (var group in account?.Groups)
{
userIdentity.AddClaim(new Claim("group", group));
}
}
}
return initialUser;
}
}
创建自定义用户帐户:
public class CustomUserAccount : RemoteUserAccount
{
[JsonPropertyName("groups")]
public string[] Groups { get; set; }
[JsonPropertyName("roles")]
public string[] Roles { get; set; }
}
这些角色现在可以通过 AuthorizeView 组件(在您的 page.razor 上)获得:
<AuthorizeView Roles="EditCustomer"> Content only available to EditCustomer Role</AuthorizeView>
我已经使用 Azure AD 单一原则设置了身份验证。使用应用程序角色进行授权。
API 是带有 swagger 客户端的 asp.net 核心 3.1。一切都经过测试,一切正常。 Blazor 客户端可以登录。但是 user.Identity 没有角色声明,因此 AuthorizeView 无法正常工作。
那我错过了什么?一个 nuget 包还是我必须将角色映射到自定义用户帐户?
这是我的具有 3 个角色的 jwt 令牌
{
"aud": "https://testacompany.onmicrosoft.com/customeredit-api",
"iss": "https://sts.windows.net/8506d453-347c-4239-adf7-602ca98f4853/",
"iat": 1614587145,
"nbf": 1614587145,
"exp": 1614591045,
"acr": "1",
"aio": "AUQAu/8TAAAAf2oBifx9vVtfPJXmlKP/MOzvpF3Flcnlt2BLFHe8B9K2NUFrQF4XP69vRu8voLMK5eo8zGgIl/aTdHOnrqmGaQ==",
"amr": [
"pwd"
],
"appid": "1a454d3f-329b-490d-b0fe-521bf6f61478",
"appidacr": "0",
"email": "xxx@acompany.dk",
"given_name": "Martin",
"idp": "https://sts.windows.net/3443ebe9-de49-471a-b7e5-9f9abfafac0c/",
"ipaddr": "131.165.55.123",
"name": "Martin Andersen",
"oid": "f121e73d-f5d8-436a-aef5-954cd286e80e",
"rh": "0.AAAAU9QGhXw0OUKt92AsqY9IUz9NRRqbMg1JsP5SG_b2FHiBAOY.",
"roles": [
"EditCustomer",
"EditAgreement",
"Reader"
],
"scp": "Api.Access",
"sub": "oxMQxcyNNgU-fZMto4xwOOwrI18mlUgM1GyyNhAFmDQ",
"tid": "8506d453-347c-4239-adf7-602ca98f4853",
"unique_name": "xxx@acompany.dk",
"uti": "K-zFcTY_mUG6RNzI-FdgAA",
"ver": "1.0"
}
在 Blazor 中 Program.cs
b.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>(options =>
{
options.UserOptions.RoleClaim = "role";
b.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://testacompany.onmicrosoft.com/customeredit-api/Api.Access");
}).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState,CustomUserAccount ,CustomUserFactory>();
b.Services.AddOptions();
b.Services.AddAuthorizationCore();
我还尝试创建 CustomUserFactory
public class CustomUserFactory : AccountClaimsPrincipalFactory<CustomUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
Console.WriteLine($"User IsAuthenticated: {user.Identity.IsAuthenticated}");
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims.Any())
{
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem = account.AdditionalProperties[identity.RoleClaimType];
if (rolesElem is JsonElement roles)
{
Console.WriteLine($"JsonElement: {rolesElem}");
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
Console.WriteLine($"role: {role.GetString()}");
identity.AddClaim(new Claim(options.RoleClaim, role.GetString()));
}
}
else
{
Console.WriteLine($"roles: {roles.GetString()}");
identity.AddClaim(new Claim(options.RoleClaim, roles.GetString()));
}
}
}
}
return user;
}
}
但我想我需要解析原始 jwt 并将角色映射到我的用户。 那么如何访问 jwt 令牌?
此实施应该可以解决您的问题。我希望它包含在 .net 6+ 的未来模板中。
在 Blazor 中 Program.cs
builder.Services.AddMsalAuthentication<RemoteAuthenticationState, CustomUserAccount>
(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://testacompany.onmicrosoft.com/customeredit-api/Api.Access");
options.UserOptions.RoleClaim = "role";
}).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount, CustomUserFactory>();
创建自定义用户工厂:
public class CustomUserFactory : AccountClaimsPrincipalFactory<CustomUserAccount>
{
public CustomUserFactory(IAccessTokenProviderAccessor accessor)
: base(accessor)
{
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(CustomUserAccount account, RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity.IsAuthenticated)
{
var userIdentity = (ClaimsIdentity)initialUser.Identity;
if (account?.Roles?.Length > 0)
{
foreach (var role in account?.Roles)
{
userIdentity.AddClaim(new Claim("role", role));
}
}
if (account?.Groups?.Length > 0)
{
foreach (var group in account?.Groups)
{
userIdentity.AddClaim(new Claim("group", group));
}
}
}
return initialUser;
}
}
创建自定义用户帐户:
public class CustomUserAccount : RemoteUserAccount
{
[JsonPropertyName("groups")]
public string[] Groups { get; set; }
[JsonPropertyName("roles")]
public string[] Roles { get; set; }
}
这些角色现在可以通过 AuthorizeView 组件(在您的 page.razor 上)获得:
<AuthorizeView Roles="EditCustomer"> Content only available to EditCustomer Role</AuthorizeView>