简体   繁体   中英

Custom AuthenticationStateProvider in blazor project doesn't work on server side

Hi all! I'm trying to make my custom auth mode in Blazor WebAssembly App (this is where studio creates 3 projects - client, server, shared). Idea is avoid IS4 auth and make my oun "internal" user for test purposes and understand the work of auth mech as well. I'm doing it by creating my custom AuthenticationStateProvider? like it shown in official docs . This is my AuthenticationStateProvider class:

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    private bool _isLoggedIn = true;

    //this is a parameter defininng whether user logged in or not
    //changed by reflection
    public bool IsLoggedIn
    {
        get
        {
            return _isLoggedIn;
        }
        set
        {
            _isLoggedIn = value;
            NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
        }
    }
    private static CustomAuthStateProvider _myInstance = null;



    public Serilog.ILogger _logger { get; set; }

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

        Task<AuthenticationState> rez;

     if (IsLoggedIn)
        {
            identity = new ClaimsIdentity(new[]
            {
            new Claim(ClaimTypes.Name, "User01"),
            }, "Fake authentication type");
        }
        else
        {
            identity = new ClaimsIdentity();
        }
        var user = new ClaimsPrincipal(identity);

        rez = Task.FromResult(new AuthenticationState(user));

        return rez;

    }

    public static CustomAuthStateProvider GetMyInstance(Serilog.ILogger logger = null, string mySide = "")
    {
        //implementing singleton
        if (_myInstance == null)
        {
            _myInstance = new CustomAuthStateProvider();
            _myInstance._logger = logger;
        }
        return _myInstance;
    }
}

This is how i plug it on client side (program.cs)

builder.Services.AddSingleton<AuthenticationStateProvider>(x => CustomAuthStateProvider.GetMyInstance(Log.Logger, "Client"));

This is how i plug it on server side (startup.cs)

services.AddSingleton<AuthenticationStateProvider, CustomAuthStateProvider>();

Problem: it works fine on client side, that means i can login, logout and use AutorizeView and similar tags. But It doesnt' t work on server side, that means HttpContext.User doesn't see any user authenticated and i cant use [Authorize] and similar attributes. What i'm doing wrong? How HttpContext.User is connected to AuthenticationStateProvider in asp.net core project? Thanks;-)

Here's a very simple Test AuthenticationStateProvider I hashed up recently for a Server Side project.

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

namespace Blazor.Auth.Test
{
    public class TestAuthenticationStateProvider : AuthenticationStateProvider
    {

        public TestUserType UserType { get; private set; } = TestUserType.None;

        private ClaimsPrincipal Admin
        {
            get
            {
                var identity = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Sid, "985fdabb-5e4e-4637-b53a-d331a3158680"),
                    new Claim(ClaimTypes.Name, "Administrator"),
                    new Claim(ClaimTypes.Role, "Admin")
                }, "Test authentication type");
                return new ClaimsPrincipal(identity);
            }
        }

        private ClaimsPrincipal User
        {
            get
            {
                var identity = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Sid, "024672e0-250a-46fc-bd35-1902974cf9e1"),
                    new Claim(ClaimTypes.Name, "Normal User"),
                    new Claim(ClaimTypes.Role, "User")
                }, "Test authentication type");
                return new ClaimsPrincipal(identity);
            }
        }

        private ClaimsPrincipal Visitor
        {
            get
            {
                var identity = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Sid, "3ef75379-69d6-4f8b-ab5f-857c32775571"),
                    new Claim(ClaimTypes.Name, "Visitor"),
                    new Claim(ClaimTypes.Role, "Visitor")
                }, "Test authentication type");
                return new ClaimsPrincipal(identity);
            }
        }

        private ClaimsPrincipal Anonymous
        {
            get
            {
                var identity = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Sid, "0ade1e94-b50e-46cc-b5f1-319a96a6d92f"),
                    new Claim(ClaimTypes.Name, "Anonymous"),
                    new Claim(ClaimTypes.Role, "Anonymous")
                }, null);
                return new ClaimsPrincipal(identity);
            }
        }

        public override Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var task = this.UserType switch
            {
                TestUserType.Admin => Task.FromResult(new AuthenticationState(this.Admin)),
                TestUserType.User => Task.FromResult(new AuthenticationState(this.User)),
                TestUserType.None => Task.FromResult(new AuthenticationState(this.Anonymous)),
                _ => Task.FromResult(new AuthenticationState(this.Visitor))
            };
            return task;
        }

        public Task<AuthenticationState> ChangeUser(TestUserType userType)
        {
            this.UserType = userType;
            var task = this.GetAuthenticationStateAsync();
            this.NotifyAuthenticationStateChanged(task);
            return task;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Blazor.Auth.Test
{
    public enum TestUserType
    {
        None,
        Visitor,
        User,
        Admin
    }
}

Startup regstration:

services.AddScoped<AuthenticationStateProvider, TestAuthenticationStateProvider>();

Simple Component I add to NavMenu to switch users.

<AuthorizeView>
    <Authorized>
        <div class="m-1 p-1 text-white">
            @user.Identity.Name
        </div>
    </Authorized>
    <NotAuthorized>
        <div class="m-1 p-1 text-white">
            Not Logged In
        </div>
    </NotAuthorized>
</AuthorizeView>
<div class="m-1 p-3">
    <select class="form-control" @onchange="ChangeUser">
        @foreach (var value in Enum.GetNames(typeof(TestUserType)))
        {
            <option value="@value">@value</option>
        }
    </select>
</div>

@code {

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

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

    private System.Security.Claims.ClaimsPrincipal user;

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

    private async Task ChangeUser(ChangeEventArgs e)
    {
        var en = Enum.Parse<TestUserType>(e.Value.ToString());
        var authState = await ((TestAuthenticationStateProvider)AuthState).ChangeUser(en);
        this.user = authState.User;
    }
}

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