【问题标题】:Authorize with roles is not working in .NET 5.0 Blazor Client app使用角色授权在 .NET 5.0 Blazor 客户端应用程序中不起作用
【发布时间】:2022-01-04 18:45:14
【问题描述】:

我有一个 .NET 5.0 Blazor 客户端应用程序,但无法使用 [Authorize(Roles="Admin")]AuthorizeView 标记。

我也搭建了身份页面:

我正在使用使用 Cosmos Db 的自定义身份实现:https://github.com/pierodetomi/efcore-identity-cosmos

我知道 Blazor 客户端项目模板中的角色授权是一个问题:https://github.com/dotnet/AspNetCore.Docs/issues/17649#issuecomment-612442543

我尝试了上述 Github 问题线程和以下 SO 答案中提到的解决方法:https://stackoverflow.com/a/64798061/6181928

...不过,我无法让它工作。

具有讽刺意味的是,IsInRoleAsync 方法在登录到应用程序后甚至都没有被调用。我在自定义 CosmosUserStore 类中对其实现应用了一个断点,它没有被命中。

使用管理员用户登录应用程序后,浏览器控制台会显示:

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDatabaseDeveloperPageExceptionFilter();

        services.AddCosmosIdentity<MyDbContext, IdentityUser, IdentityRole>(
          // Auth provider standard configuration (e.g.: account confirmation, password requirements, etc.)
          options => options.SignIn.RequireConfirmedAccount = true,
          options => options.UseCosmos(
              "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
              "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
              databaseName: "xxxxxxxxxxxxxxxxxxxxxxxxx"
          ),
          addDefaultTokenProviders: true
        ).AddDefaultUI().AddRoles<IdentityRole>();

        services.AddScoped<IUsersRepository, UsersRepository>();

        services.AddIdentityServer().AddApiAuthorization<IdentityUser, MyDbContext>(options =>
        {
            options.IdentityResources["openid"].UserClaims.Add("role");
            options.ApiResources.Single().UserClaims.Add("role");
        });

        // Need to do this as it maps "role" to ClaimTypes.Role and causes issues
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

        services.AddAuthentication()
            .AddIdentityServerJwt();

        services.AddControllersWithViews();
        services.AddRazorPages();
    }

Program.cs

    public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("#app");

        builder.Services.AddHttpClient("IdentityDocApp.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
            .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

        // Supply HttpClient instances that include access tokens when making requests to the server project
        builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("IdentityDocApp.ServerAPI"));

        builder.Services.AddHttpClient();
        builder.Services.AddScoped<IManageUsersService, ManageUsersService>();
        builder.Services.AddBlazorTable();

        builder.Services.AddApiAuthorization();
        builder.Services.AddApiAuthorization(options =>
        {
            options.UserOptions.RoleClaim = "role";
        });

        await builder.Build().RunAsync();
    }
}

App.razor

NavMenu.razor

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
            <span class="oi oi-home" aria-hidden="true"></span> Home
        </NavLink>
    </li>
    <AuthorizeView Roles="Admin">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="users">
                <span class="oi oi-person" aria-hidden="true"></span> Users
            </NavLink>
        </li>
    </AuthorizeView>
</ul>

ManageUsers.razor

管理用户控制器

数据库在 UserRoles 集合中有正确的数据。没有问题。

那么,可能是什么问题?我做错了什么?

更新:

这很尴尬,但我在自定义用户存储中的IsInRoleAsync 实现不正确。一旦我修复它,问题就消失了。

我只在服务器端的Startup.cs使用如下代码:

    services.AddIdentityServer()
        .AddApiAuthorization<IdentityUser, MyDbContext>(options =>
        {
            options.IdentityResources["openid"].UserClaims.Add("name");
            options.ApiResources.Single().UserClaims.Add("name");
            options.IdentityResources["openid"].UserClaims.Add("role");
            options.ApiResources.Single().UserClaims.Add("role");
        });

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

在客户端的Program.cs我只使用builder.Services.AddApiAuthorization();

感谢@MrC aka Shaun Curtis 让我知道问题出在服务器端。

【问题讨论】:

  • 请将您的App.razor 添加到您的问题中。
  • @MrCakaShaunCurtis App.razor 已添加问题。
  • 谢谢。从登录过程返回您的应用程序后,您是否在App 中点击 ?或者你登陆的是哪个页面?
  • 谢谢,@MrCakaShaunCurtis。以管理员用户登录后,它登陆Index.razor。屏幕截图:ibb.co/Wthd42b 当我尝试访问包含 Authorize 和 AuthorizeView 标签的“/users”时,它给出“您无权访问此资源”。截图:ibb.co/SnVnqB9
  • 查看答案以获得更多测试。这不是答案,但您不能将代码放在评论中!

标签: authorization blazor .net-5 blazor-webassembly asp.net-authorization


【解决方案1】:

将此粘贴​​到您的索引页面中,以便您查看用户信息:

@if (user is not null)
{
    <h3>@user.Identity.Name</h3>
    <div class="m-2 p-2">
        Is Authenticated: @user.Identity.IsAuthenticated
    </div>
    <div class="m-2 p-2">
        Authentication Type: @user.Identity.AuthenticationType
    </div>
    <div class="m-2 p-2">
        Admin Role: @user.IsInRole("Admin")
    </div>
    <div class="m-2 p-2">
        <h5>Claims</h5>
        @foreach (var claim in user.Claims)
        {
            <span>
                @claim.Type
            </span>
            <span>:</span>
            <span>
                @claim.Value
            </span>
            <br />
        }
    </div>
}
else
{
    <div class="m-2 p-2">
        No User Exists
    </div>
}

@code {
    [CascadingParameter] public Task<AuthenticationState> AuthTask { get; set; }

    private System.Security.Claims.ClaimsPrincipal user;

    protected async override Task OnInitializedAsync()
    {
        var authState = await AuthTask;
        this.user = authState.User;
    }
}

你应该得到这样的东西:

这显示了来自身份验证提供程序的标头中的身份验证数据中传递了哪些角色。这应该包括角色。

更新

删除:

// Need to do this as it maps "role" to ClaimTypes.Role and causes issues
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

【讨论】:

  • 谢谢。我试过了,得到了这个:ibb.co/YjLLPJC 管理员角色检查调用返回 false。
  • 查看更新的答案
  • 刚刚删除了上述行并再次尝试。不幸的是,它没有效果。我得到的结果与我之前的评论相同。 “角色”仍然不是声明​​列表的一部分。
  • 所以问题在于身份验证,而不是授权。您的 JWT 身份验证颁发者未将角色数据添加到 JWT 令牌。可能是 Cosmos DB 接口。在这一点上,我退出了,因为我没有经验!
  • 我明白了。基本上,“角色”声明不是服务器应用程序返回的 jwt 令牌的一部分。你能告诉我asp.net身份的哪个接口负责添加“角色”声明吗?
猜你喜欢
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2018-05-28
  • 1970-01-01
  • 2021-09-07
  • 2020-05-20
  • 2015-01-06
  • 1970-01-01
相关资源
最近更新 更多