服务器端Blazor Autorize属性不起作用

时间:2020-05-17 17:19:51

标签: c# .net authentication blazor

我有一个问题,使用服务器端Blazor,authorize属性在页面上不起作用。

我关注了以下文档:https://docs.microsoft.com/fr-fr/aspnet/core/security/blazor/?view=aspnetcore-3.1

还有https://gunnarpeipman.com/client-side-blazor-authorizeview/,这有点过时了。

这是自定义提供程序:

using Microsoft.AspNetCore.Components.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace CustomAuth
{
    public class MyAuthenticationStateProvider : AuthenticationStateProvider
    {
        public static bool IsAuthenticated { get; set; }
        public static bool IsAuthenticating { get; set; }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            ClaimsIdentity identity;

            if (IsAuthenticating)
            {
                return null;
            }
            else if (IsAuthenticated)
            {
                identity = new ClaimsIdentity(new List<Claim>
                        {
                            new Claim(ClaimTypes.Name, "TestUser")

                        }, "WebApiAuth");
            }
            else
            {
                identity = new ClaimsIdentity();
            }

            return await Task.FromResult(new AuthenticationState(new ClaimsPrincipal(identity)));
        }

        public void NotifyAuthenticationStateChanged()
        {
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }
    }
}

在我的login.razor中:

@page "/Login"
@using CustomAuth


@inject MyAuthenticationStateProvider MyAuthStateProvider


<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<button @onclick="@(() => UpdateAuthentication(true))">
    Set authenticated
</button>
<button @onclick="@(() => UpdateAuthentication(false))">
    Set anonymous
</button>
<button @onclick="@(() => UpdateAuthentication(null))">
    Set authenticating
</button>
@code
{
    private void UpdateAuthentication(bool? isAuthenticated)
    {
        if (!isAuthenticated.HasValue)
        {
            MyAuthenticationStateProvider.IsAuthenticating = true;
        }
        else
        {
            MyAuthenticationStateProvider.IsAuthenticating = false;
            MyAuthenticationStateProvider.IsAuthenticated = isAuthenticated.Value;
        }

        MyAuthStateProvider.NotifyAuthenticationStateChanged();
    }

在我的index.razor中:

@page "/"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject MyAuthenticationStateProvider MyAuthStateProvider

<h3>ClaimsPrincipal Data</h3>

<a href="/Login">Login</a>

<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>

<p>@_authMessage</p>

@if (_claims.Count() > 0)
{
    <ul>
        @foreach (var claim in _claims)
        {
            <li>@claim.Type &ndash; @claim.Value</li>
        }
    </ul>
}

<p>@_surnameMessage</p>

@code {
    private string _authMessage;
    private string _surnameMessage;
    private IEnumerable<Claim> _claims = Enumerable.Empty<Claim>();


    private async Task GetClaimsPrincipalData()
    {
        var authState = await MyAuthStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            _authMessage = $"{user.Identity.Name} is authenticated.";
            _claims = user.Claims;
            _surnameMessage =
                $"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
        }
        else
        {
            _authMessage = "The user is NOT authenticated.";
        }
    }

然后是我的app.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <CascadingAuthenticationState>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </CascadingAuthenticationState>
    </NotFound>
</Router>

我的startup.cs:

public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; }

    public IConfiguration Configuration { get; }

    // 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.AddAuthenticationCore();
        services.AddScoped<MyAuthenticationStateProvider>();
        services.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<MyAuthenticationStateProvider>());
        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddSingleton<WeatherForecastService>();            

    }

    // 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");
            // 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.UseHttpsRedirection();
        app.UseStaticFiles();            

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

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

public IConfiguration Configuration { get; } // 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.AddAuthenticationCore(); services.AddScoped<MyAuthenticationStateProvider>(); services.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<MyAuthenticationStateProvider>()); services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<WeatherForecastService>(); } // 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"); // 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.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); } }

问题是授权组件不起作用,当我进入登录页面时,当我授权后,当我单击计数器组件时,我会收到“未授权”消息!

我们将不胜感激,我已经尝试过解决问题,直到昨天凌晨3点为止!

非常感谢,

拉斐尔

1 个答案:

答案 0 :(得分:3)

我能在您的代码中找到阻止应用程序按预期方式运行的唯一原因与订单有关。

此设置:

    services.AddAuthenticationCore();
    services.AddScoped<MyAuthenticationStateProvider>();
    services.AddScoped<AuthenticationStateProvider>(provider => 
    provider.GetRequiredService<MyAuthenticationStateProvider>());
    services.AddRazorPages();
    services.AddServerSideBlazor();
    services.AddSingleton<WeatherForecastService>();  

应该这样订购:

    services.AddAuthenticationCore();
    services.AddRazorPages();
    services.AddServerSideBlazor();
    services.AddScoped<MyAuthenticationStateProvider>();
    services.AddScoped<AuthenticationStateProvider>(provider => 
    provider.GetRequiredService<MyAuthenticationStateProvider>());
    services.AddSingleton<WeatherForecastService>();

您首先必须添加Razor Pages服务和Blazor Server App服务,然后才添加自定义服务。

运行您的应用程序,单击“计数器...。未显示授权文本”。返回“索引”页面,单击“登录”,然后选择“设置身份验证”。现在返回“计数器”页面...允许访问。

现在尝试自动执行此操作...单击“计数器”时,它应将我重定向到登录页面,而当单击“设置身份验证”时,它会将我重定向到“计数器”页面(允许访问)。

希望这对您有帮助...