简体   繁体   中英

Server-side Blazor Autorize Attribute is not working

I have a problem, the authorize attribute is not working on a page, using Server-side Blazor.

I have followed the following docs: https://learn.microsoft.com/fr-fr/as.net/core/security/blazor/?view=as.netcore-3.1

And https://gunnarpeipman.com/client-side-blazor-authorizeview/ , which is a bit outdated.

So here's the custom provider:

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());
        }
    }
}

In my 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();
    }

And in my 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.";
        }
    }

And then my 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>

My 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/as.netcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); } }

The problem is the authorize component is not working, when I go to the login page and after I authorize, I get the Unauthorize message when I click on the counter component !

@page "/counter"
@attribute [Authorize]
<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Any help would really be appreciated, I have tried to solve this problem yesterday until 3 am without success!

Many thanks,

Raphaël

The only reason I could locate in your code that prevent the app from working as intended is related to order.

This setting:

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

Should be ordered like this:

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

You first have to add the Razor Pages services and the Blazor Server App services, and only then add custom services.

Run your app, click Counter... Not Authorized text is displayed. Go back to the Index page, click login, and then choose Set Authenticated. Now go back to the Counter page... Access is allowed.

Now try to do that automatically... When I click Counter, it should redirect me to the login page, and when I click set authenticated, it redirects me to the Counter page (access allowed).

Hope this helps...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM