【问题标题】:User.Identity.Name is returning null even after being authorized through identityserverUser.Identity.Name 即使在通过身份服务器授权后也返回 null
【发布时间】:2021-06-30 20:48:50
【问题描述】:

在授权后尝试检索当前登录用户的名称时,User.Identity.Name 为空。如果我从IdentityServer 成功登录,我似乎不明白为什么它为空,它会将我重定向回我的 blazor 项目。

在我的 blazor 项目中,我设置了以下代码:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();


            services.AddSingleton(sp => new HttpClient { BaseAddress = new Uri("http://localhost:36626") }); // WebApi project

            services.AddTransient<IWeatherForecastServices, WeatherForecastServices>();

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)

                .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
                {
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.SignOutScheme = OpenIdConnectDefaults.AuthenticationScheme;

                    options.Authority = "https://localhost:5443"; // IdentityServer Project
                    options.ClientId = "interactive";
                    options.ClientSecret = "KEY";

                    options.ResponseType = "code";
                  
                    options.Scope.Add("profile"); // default scope
                    options.Scope.Add("scope2");
                    options.Scope.Add("roles");
                    options.Scope.Add("permissions");
                    options.ClaimActions.MapUniqueJsonKey("role", "role");
                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                   
                });
            services.AddScoped<TokenProvider>();

            services.AddCors(options =>
            {
                options.AddPolicy("Open", builder => builder.AllowAnyOrigin().AllowAnyHeader());
            }
            );
        }

        // 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.UseCors("Open");

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

Index.razor 这里变量“名称”为空:

@page "/"
@inject AuthenticationStateProvider GetAuthenticationStateAsync

<AuthorizeView>
    <Authorized>
        <h3>Welcome, <b>@Name</b></h3>
    </Authorized>
    <NotAuthorized>  
        <h3>You are signed out!!</h3>
    </NotAuthorized>
</AuthorizeView>

@code{

    private string Name;

    protected override async Task OnInitializedAsync()
    {
        var authstate = await GetAuthenticationStateAsync.GetAuthenticationStateAsync();
        var user = authstate.User;
        var name = user.Identity.Name;
        Name = name;
    }
}

我的Login.cshtml.cs

    public class LoginModel : PageModel
    {
        public async Task<IActionResult> OnGetAsync(string redirectUri)
        {
            // just to remove compiler warning
            await Task.CompletedTask;

            if (string.IsNullOrWhiteSpace(redirectUri))
            {
                redirectUri = Url.Content("~/");
            }
            // If user is already logged in, we can redirect directly...
            if (HttpContext.User.Identity.IsAuthenticated)
            {
                Response.Redirect(redirectUri);
            }

            return Challenge(
                new AuthenticationProperties
                {
                    RedirectUri = redirectUri
                },
                OpenIdConnectDefaults.AuthenticationScheme);
        }
   }

我的logout.cshtml.cs

    public class LogoutModel : PageModel
    {
     
        public async Task<IActionResult> OnGetAsync() // THIS METHOD DOES NOT DELETE THE AUTH COOKIES NOR REDIRECT YOU BACK TO BLAZOR APP EVEN THOUGH YOU HAVE THE REDIRECT URI OF BLAZOR
        {
            // just to remove compiler warning
            await Task.CompletedTask;
            var signOut = SignOut(
            new AuthenticationProperties
            {

                RedirectUri = "https://localhost:5445" // Blazor Project
            },
            OpenIdConnectDefaults.AuthenticationScheme,
            CookieAuthenticationDefaults.AuthenticationScheme);

            return signOut;
        }

    }

前端视图:

从项目开始运行:

我点击登录,这会将我重定向到身份服务器项目:

主页视图,这里应该显示当前用户登录的位置,但它没有:

当我点击注销时,它会将我重定向到身份服务器,说我已注销:

在我的 Index.razor 文件中,是否存在导致变量 Name 为空的原因?

【问题讨论】:

  • 我认为您不需要所有这些代码索引页。在&lt;h3&gt; 中您需要的唯一一行只是@context.User.Identity.Name

标签: c# razor blazor blazor-server-side


【解决方案1】:

你为什么在你的索引组件中使用?

如果您使用&lt;AuthorizeView&gt;,则不必创建AuthenticationStateProvider 对象...您可以简单地做:@context.User.Identity.Name,作为App 组件中使用的CascadingAuthenticationComponent,将AuthenticationState 对象级联到子级。如果您的 App 组件中没有 CascadingAuthenticationComponent,请添加它。

很可能没有创建身份验证状态对象...这意味着 CascadingAuthenticationComponent 和 AuthenticationStateProvider 对象都返回空值。

尝试以下方法:

注释掉以下内容:

options.Scope.Add("profile"); // default scope
options.Scope.Add("scope2");
options.Scope.Add("roles");
options.Scope.Add("permissions");
options.ClaimActions.MapUniqueJsonKey("role", "role");

并改用以下内容:

options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.TokenValidationParameters = new TokenValidationParameters
{
     NameClaimType = "name"
};

 options.UseTokenLifetime = false;

你说你已经创建了一个 IdentityServer,对吧?如果是这样,在您的 Config 文件中,您为 Client 对象的 ClientId 属性赋予了什么值? ConfigureServices 方法中的此设置: options.ClientId = "interactive"; 应该反映它。

以下是 IdentityServer4 项目中 Config.cs 文件中客户端对象的代码示例:

public static IEnumerable<Client> Clients =>
        new Client[]
        {
            new Client
            {
                ClientId = "blazor",
                AllowedGrantTypes = GrantTypes.Code,
                RequirePkce = true,
                RequireClientSecret = false,
                AllowedCorsOrigins = { "https://localhost:5001" },
                AllowedScopes = { "openid", "profile", "email", "weatherapi" },
                // where to redirect to after login
                RedirectUris = { "https://localhost:5001/authentication/login-callback" },
                PostLogoutRedirectUris = { "https://localhost:5001/" },
                Enabled = true,
                AllowOfflineAccess = true
            },
        };

【讨论】:

    猜你喜欢
    • 2020-11-26
    • 1970-01-01
    • 1970-01-01
    • 2014-02-08
    • 2015-01-06
    • 1970-01-01
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多