【问题标题】:Custom AuthenticationStateProvider in blazor project doesn't work on server sideblazor 项目中的自定义 AuthenticationStateProvider 在服务器端不起作用
【发布时间】:2021-11-29 18:46:39
【问题描述】:

大家好! 我正在尝试在 Blazor WebAssembly 应用程序中创建我的自定义身份验证模式(这是工作室创建 3 个项目的地方 - 客户端、服务器、共享)。想法是避免 IS4 身份验证,让我的“内部”用户用于测试目的,并了解身份验证机的工作。我通过创建我的自定义 AuthenticationStateProvider 来做到这一点?就像official docs 中显示的一样。这是我的 AuthenticationStateProvider 类:

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

这就是我将它插入客户端(program.cs)的方式

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

这就是我将它插入服务器端 (startup.cs) 的方式

services.AddSingleton<AuthenticationStateProvider, CustomAuthStateProvider>();

问题: 它在客户端运行良好,这意味着我可以登录、注销并使用 AutorizeView 和类似的标签。但它在服务器端不起作用,这意味着 HttpContext.User 没有看到任何经过身份验证的用户,我不能使用 [Authorize] 和类似属性。我做错了什么? HttpContext.User如何连接到asp.net核心项目中的AuthenticationStateProvider? 谢谢;-)

【问题讨论】:

  • 在这里找到类似的问题stackoverflow.com/questions/62529029/…
  • 我认为服务注册应该是Scoped的。我还在下面为您添加了我的服务器端授权测试器的代码。我已将其添加为答案,因为这是添加它的唯一方法。

标签: asp.net asp.net-core blazor asp.net-core-webapi blazor-server-side


【解决方案1】:

这是一个非常简单的测试 AuthenticationStateProvider 我最近为一个服务器端项目散列。

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
    }
}

启动注册:

services.AddScoped<AuthenticationStateProvider, TestAuthenticationStateProvider>();

我添加到 NavMenu 以切换用户的简单组件。

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

【讨论】:

  • 嗨!非常感谢您的回答)我按照您所写的那样做了服务器端,将服务器启动注册更改为 AddScoped,但仍然没有任何改变。在服务器控制器中,用户有 1 个空身份,因此它没有经过身份验证,也没有通过 [Autorize] 属性。我继续研究这个问题。我徘徊,创建控制器实例时 HttpContext 将用户带到哪里。
  • 您是在做服务器端 Blazor,还是有一个 WASM 应用程序调用“服务器端”API。如果是第二种情况,那么 API 是纯 ASPNetCore,根本不是 Blazor,我上面的代码实际上并不适用!
  • @enet 非常感谢您的回答!当您编写 'services.AddScoped(provider => provider.GetRequiredService());' 时,我已将 AuthenticationStateProvider 添加到 DI ,而我的 AuthenticationStateProvider 后代与您的相似,但没有任何改变。不过,我继续工作)
  • @MrC aka Shaun Curtis,我首先要做的是,您可以在这里创建一个包含客户端、服务器和共享项目的 Blazor Web 应用程序
  • 这是一个带有 API ASPNetCore 后端的 WASM Blazor 应用程序,而不是 Blazor Server 应用程序。忘记我的答案,它是针对 Blazor Server 应用程序的。您谈论的是在 API 控制器上的 WASM 应用程序中对用户进行身份验证?
猜你喜欢
  • 2020-03-25
  • 2020-01-05
  • 2020-03-19
  • 1970-01-01
  • 2020-10-13
  • 2020-01-22
  • 2021-12-09
  • 2020-07-08
  • 2020-09-03
相关资源
最近更新 更多