首页 > 解决方案 > 如何访问 .razor 文件之外的 AuthorizationProvider?

问题描述

我有一个带有剃须刀组件的 apsnet 核心应用程序。我使用 Discord OAuth 登录,并且可以读取 .razor 文件中的声明。

@foreach (var c in context.User.Claims)
        {
            <li>@c.Type: @c.Value</li>
        }

如何在剃须刀组件之外访问这些声明?我想在我自己的数据库中找到 ID 与登录名中的不和谐 ID 匹配的用户。

我发现我可以创建一个组件类,剃须刀组件可以从中继承,并且 AuthenticationStateProvider 包含用户/声明。但是我如何得到它或者我需要别的东西吗?

测试组件.cs:

public class TestComponent: ComponentBase
{
    public string SomeTestText { get; set; }
    private AuthenticationStateProvider asp{ get; set; }
    
    public TestComponent()
    {

        SomeTestText = "Hello World!";
        GetUser();
    }

    private async Task GetUser()
    {
        var authState = await asp.GetAuthenticationStateAsync(); // asp is null
        var user = authState.User;
        SomeTestText = user.Claims.First().Value;
    }
}

测试剃须刀:

@page "/test"
@inherits Models.TestComponent;

<h1>@SomeTestText</h1>

编辑

只是添加 [Inject] 对我不起作用;它仍然为空。

由于它是 ComponentBase 而不是 PageModel(?) 我无法在构造函数中注入 ClaimsPrincipal 。我也用 [Inject] 对其进行了测试,但它也不起作用。

这是我的 Startup.cs 以获得更多上下文:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SlpyGrdn.Database;
using SlpyWeb.OAuth.Discord;
using System;
using System.Security.Claims;


namespace SlpyWeb
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup( IConfiguration configuration )
        {
            Configuration = new ConfigurationBuilder()
                .AddConfiguration(configuration)
                .AddEnvironmentVariables()
                .Build();

        }


        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices( IServiceCollection services )
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();

            services.AddAuthentication(opt =>
            {
                opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                opt.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                opt.DefaultChallengeScheme = DiscordEndPoints.AuthenticationScheme;
            })
            .AddCookie()
            .AddDiscord(x =>
            {   
                x.AppId = Environment.GetEnvironmentVariable("DISCORD_APP_ID");
                x.AppSecret = Environment.GetEnvironmentVariable("DISCORD_APP_SECRET");
                x.SaveTokens = true;
            });
            services.AddDbContext<SlpyDbContext>(options => options.UseNpgsql(Environment.GetEnvironmentVariable("CONNECTION_STRING")));


            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped(svc => svc.GetService<IHttpContextAccessor>()?.HttpContext?.User ?? new ClaimsPrincipal());
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure( IApplicationBuilder app, IWebHostEnvironment env )
        {
            if ( env.IsDevelopment() )
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // app.UseDeveloperExceptionPage();
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
            });
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
                endpoints.MapControllers();
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}

编辑 2

我找到了解决方法:

@page "/test"

@inherits Models.TestComponent;

<h3>Test</h3>

<p>@SomeTestText</p>

@code { 


   [CascadingParameter] private AuthenticationStateProvider asp { get; set; }

   protected override async Task OnInitializedAsync()
   {

       var authState = await asp.GetAuthenticationStateAsync();
       var user = authState.User;
       DoSomething(user);

       await base.OnInitializedAsync();
   }
}

“DoSomething”是TestComponent 中的一个方法。所以我只是将用户声明转发给我的班级。不是最好的解决方案,但它现在可以工作。

标签: c#asp.net-coreblazor

解决方案


您可以使用 [inject] 属性来@inject 向 DI 注册的类。

[Inject] private AuthenticationStateProvider asp {get; set;}

推荐阅读