.net core 未强制webassembly blazor客户端应用程序中的授权视图

.net core 未强制webassembly blazor客户端应用程序中的授权视图,.net-core,azure-active-directory,blazor-webassembly,user-roles,azure-rbac,.net Core,Azure Active Directory,Blazor Webassembly,User Roles,Azure Rbac,我有一个在webassembly blazor中开发的客户端应用程序,受Azure AD的保护,在Azure AD中定义了它的注册和3个角色,并将其分配给用户 用户登录后,将用户重定向到显示声明集的配置文件页面 Claim Type Value oid 091fadf9-b0bd-4583-b55d-XXXX preferred_username XX roles ["Administrat

我有一个在webassembly blazor中开发的客户端应用程序,受Azure AD的保护,在Azure AD中定义了它的注册和3个角色,并将其分配给用户

用户登录后,将用户重定向到显示声明集的配置文件页面

Claim Type            Value
oid                   091fadf9-b0bd-4583-b55d-XXXX
preferred_username    XX
roles                 ["Administrator"]
根据用户角色,将显示不同的UI,但这不起作用

<AuthorizeView Roles="Administrator">
   ADMIN UI
</AuthorizeView>

管理用户界面
我的程序类如下所示:

 public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");
            //builder.Logging.SetMinimumLevel(LogLevel.Debug);


            ////builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddScoped<CustomAuthorizationMessageHandler>();

            builder.Services.AddHttpClient("myAPI",
               client => client.BaseAddress = new Uri("private API URL"))
              .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();

            builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
                .CreateClient("myAPI"));

           builder.Services.AddMsalAuthentication(options =>
            {
               builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add(myAPI);
                options.UserOptions.RoleClaim = "roles";
            });

            await builder.Build().RunAsync();
        }
公共静态异步任务主(字符串[]args)
{
var builder=WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add(“应用程序”);
//builder.Logging.SetMinimumLevel(LogLevel.Debug);
////addScope(sp=>newHttpClient{BaseAddress=newURI(builder.HostenEnvironment.BaseAddress)});
builder.Services.addScope();
builder.Services.AddHttpClient(“myAPI”,
client=>client.BaseAddress=新Uri(“私有API URL”))
.AddHttpMessageHandler();
builder.Services.addScope(sp=>sp.GetRequiredService()
.CreateClient(“myAPI”);
builder.Services.AddMsalAuthentication(选项=>
{
builder.Configuration.Bind(“AzureAd”,options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add(myAPI);
options.UserOptions.RoleClaim=“角色”;
});
等待builder.Build().RunAsync();
}
我有一个用户支持的类:

 public class UserClaimsBase: ComponentBase
    {
        // AuthenticationStateProvider service provides the current user's ClaimsPrincipal data.
        [Inject]
        private AuthenticationStateProvider AuthenticationStateProvider { get; set;
        }
        protected string _authMessage;
        protected IEnumerable<Claim> _claims = Enumerable.Empty<Claim>();

        // Defines list of claim types that will be displayed after successfull sign-in.
        private string[] returnClaims = { "name", "preferred_username", "tid", "oid", "roles" };

        protected override async Task OnInitializedAsync()
        {
            await GetClaimsPrincipalData();
        }

        /// <summary>
        /// Retrieves user claims for the signed-in user.
        /// </summary>
        /// <returns></returns>
        private async Task GetClaimsPrincipalData()
        {
            // Gets an AuthenticationState that describes the current user.
            var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();

            var user = authState.User;

            // Checks if the user has been authenticated.
            if (user.Identity.IsAuthenticated)
            {
                _authMessage = $"{user.Identity.Name} is authenticated.";

                // Sets the claims value in _claims variable.
                // The claims mentioned in returnClaims variable are selected only.
                _claims = user.Claims.Where(x => returnClaims.Contains(x.Type));
            }
            else
            {
                _authMessage = "The user is NOT authenticated.";
            }
        }
    }
public类UserClaimsBase:ComponentBase
{
//AuthenticationStateProvider服务提供当前用户的ClaimsPrincipal数据。
[注入]
私有AuthenticationStateProvider AuthenticationStateProvider{get;set;
}
受保护的字符串\u authMessage;
受保护的IEnumerable_声明=Enumerable.Empty();
//定义成功登录后将显示的索赔类型列表。
私有字符串[]returnClaims={“名称”、“首选用户名”、“tid”、“oid”、“角色”};
受保护的重写异步任务OnInitializedAsync()
{
等待GetClaimsPrincipalData();
}
/// 
///检索已登录用户的用户声明。
/// 
/// 
专用异步任务GetClaimsPrincipalData()
{
//获取描述当前用户的AuthenticationState。
var authState=等待AuthenticationStateProvider.GetAuthenticationStateAync();
var user=authState.user;
//检查用户是否已通过身份验证。
if(user.Identity.IsAuthenticated)
{
_authMessage=$“{user.Identity.Name}已通过身份验证。”;
//在_claims变量中设置索赔值。
//仅选择returnClaims变量中提到的索赔。
_claims=user.claims.Where(x=>returnClaims.Contains(x.Type));
}
其他的
{
_authMessage=“用户未通过身份验证。”;
}
}
}
这里可能出了什么问题? 我不确定我错过了什么?
非常感谢您的帮助。

关于此问题,请参考以下步骤

  • 在Azure广告应用程序中定义
  • 在应用程序清单中添加以下内容

    "appRoles": [
            
            {
                "allowedMemberTypes": [
                    "User",
                    "Application"
                ],
                "description": "admin",
                "displayName": "Admin",
                "id": "d1c2ade8-98f8-45fd-aa4a-6d06b957c66f",
                "isEnabled": true,
                "lang": null,
                "origin": "Application",
                "value": "admin"
            },
            {
                "allowedMemberTypes": [
                    "User",
                    "Application"
                ],
                "description": "access database test",
                "displayName": "Test",
                "id": "d1c2ade8-98f8-45fd-aa4a-6d06b947c66f",
                "isEnabled": true,
                "lang": null,
                "origin": "Application",
                "value": "test"
            }
        ],
    
  • 配置应用程序

  • a。包装

     <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.1" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.1" PrivateAssets="all" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.1" PrivateAssets="all" />
        <PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" Version="3.2.1" />
        <PackageReference Include="System.Net.Http.Json" Version="3.2.0" />
    
  • 认证
  • 试验
  • 我的页面

    @page "/counter"
    @using Microsoft.AspNetCore.Authorization
    @attribute [Authorize(Roles = "admin")]
    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private async Task IncrementCount()
        {
    
            currentCount++;
        }
    }
    
    @page”/counter
    @使用Microsoft.AspNetCore.Authorization
    @属性[授权(Roles=“admin”)]
    柜台
    当前计数:@currentCount

    点击我 @代码{ 私有int currentCount=0; 专用异步任务递增计数() { currentCount++; } }
    我的用户

    结果

    这是最直接的答案。谢谢
    using System;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
    using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Microsoft.Graph;
    
    public class CustomAccountFactory
        : AccountClaimsPrincipalFactory<CustomUserAccount>
    {
        private readonly ILogger<CustomAccountFactory> logger;
        private readonly IServiceProvider serviceProvider;
    
        public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
            IServiceProvider serviceProvider,
            ILogger<CustomAccountFactory> logger)
            : base(accessor)
        {
            this.serviceProvider = serviceProvider;
            this.logger = logger;
        }
        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;
    
                foreach (var role in account.Roles)
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                }
            }
    
            return initialUser;
        }
    }
    
     builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
                     CustomUserAccount>(options =>
                     {
                         builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                        
                         options.UserOptions.RoleClaim = "appRole";
                     }).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount,
                 CustomAccountFactory>();
    
    # add the following code in the page according to your need
    @using Microsoft.AspNetCore.Authorization
    @attribute [Authorize(Roles = "admin")]
    
    @page "/counter"
    @using Microsoft.AspNetCore.Authorization
    @attribute [Authorize(Roles = "admin")]
    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private async Task IncrementCount()
        {
    
            currentCount++;
        }
    }