Как работает управление состояниями претензий в Blazor Server?

Я реализовал Identity Server для потока кода аутентификации.

Как правильно отстаивать претензии (в OnTicketReceived или OnTicketValidated как показано ниже), чтобы при последующих вызовах страниц Blazor я мог получать User aka ClaimPrincipal заселен для моего использования?

Вот код промежуточного программного обеспечения моего сервера ресурсов:

          public void ConfigureServices(IServiceCollection services)
    {
          //....

        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
          {
              options.SignIn.RequireConfirmedAccount = false;
              options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);

              options.SignIn.RequireConfirmedEmail = false;
          })
            .AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<SomeContext>()
            .AddDefaultTokenProviders();

Интеграция промежуточного программного обеспечения:

             services.AddAuthentication(options =>
        {
            options.DefaultScheme = "cookie";
            options.DefaultChallengeScheme = "oidc";
            options.DefaultSignOutScheme = "oidc";
        })
            .AddCookie("cookie", options =>
            {
                options.Cookie.Name = "__Host-bff";
                options.Cookie.SameSite = SameSiteMode.Strict;
            })
            .AddOpenIdConnect("oidc", options =>
            {
                options.Authority = "https://localhost:5001";
                options.ClientId = "mvc.code";
                options.ClientSecret = "secret";
                options.ResponseType = "code";
                options.ResponseMode = "query";

                options.GetClaimsFromUserInfoEndpoint = true;
                options.MapInboundClaims = false;
                options.SaveTokens = true;

                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                

                //Critical Parts
                options.TokenValidationParameters = new()
                {
                    NameClaimType = "name",
                    RoleClaimType = "role"
                };

Обратный вызов с аутентификацией от сервера идентификации выглядит следующим образом:

                      options.Events.OnTicketReceived = async n =>
                {
                    var serviceProvider = n.HttpContext.RequestServices;
                    var accountService = serviceProvider.GetService<IAccountService>() ?? throw new ArgumentNullException("serviceProvider.GetService<IAccountService>()");

                    

Я пробовал использовать BlazoredSessionStorage и т. Д., Но, кажется, слишком рано вызывать это. Нам нужно подождать, пока OnPrerender или OnInit

Я тоже пробовал CustomTokenStore. Но как запрос от cookie возвращается на сервер?

                 var svc = n.HttpContext.RequestServices.GetRequiredService<IUserAccessTokenStore>();
                  
                    if (n.Principal != null)
                    {
                        var userName = n.Principal.FindFirst(x => x.Type == "name")?.Value;


                        await accountService.UserCreateAsync(new NewAccount
                        {
                            Username = userName,
                            FirstName = userFirstName,
                            LastName = userLastName,
                            //ContactId = 100,
                            TenantId = 1
                        });
                        await (authProvider as SomeAuthenticationStateProvider).LoginAsync(new AuthenticationLogin { Username = userName }, 24 * 60);
                    }
                };

       public class CustomTokenStore : IUserAccessTokenStore
{
    ConcurrentDictionary<string, UserAccessToken> _tokens = new ConcurrentDictionary<string, UserAccessToken>();

    public Task ClearTokenAsync(ClaimsPrincipal user, UserAccessTokenParameters parameters = null)
    {
        var sub = user.FindFirst("sub").Value;
        _tokens.TryRemove(sub, out _);
        return Task.CompletedTask;
    }

    public Task<UserAccessToken> GetTokenAsync(ClaimsPrincipal user, UserAccessTokenParameters parameters = null)
    {
        var sub = user.FindFirst("sub").Value;
        _tokens.TryGetValue(sub, out var value);
        return Task.FromResult(value);
    }

    public Task StoreTokenAsync(ClaimsPrincipal user, string accessToken, DateTimeOffset expiration, string refreshToken = null, UserAccessTokenParameters parameters = null)
    {
        var sub = user.FindFirst("sub").Value;
        var token = new UserAccessToken
        {
            AccessToken = accessToken,
            Expiration = expiration,
            RefreshToken = refreshToken
        };
        _tokens[sub] = token;
        return Task.CompletedTask;
    }
}

3 ответа

      services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
                .AddAzureAD(options => Configuration.Bind("AzureAd", options));

            services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
            {

                options.ClaimActions.Add(new CustomClaimsFactory(
                                        "userName",
                                        "XXXXX@outlook.com"
                                    ));
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    // Instead of using the default validation (validating against a single issuer value, as we do in
                    // line of business apps), we inject our own multitenant validation logic
                    ValidateIssuer = false,

                    // If the app is meant to be accessed by entire organizations, add your issuer validation logic here.
                    //IssuerValidator = (issuer, securityToken, validationParameters) => {
                    //    if (myIssuerValidationLogic(issuer)) return issuer;
                    //}
                };

                options.Events = new OpenIdConnectEvents
                {
                    OnTicketReceived = context =>
                    {
                        // If your authentication logic is based on users then add your logic here
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        context.Response.Redirect("/Error");
                        context.HandleResponse(); // Suppress the exception
                        return Task.CompletedTask;
                    },
                    // If your application needs to do authenticate single users, add your user validation below.
                    //OnTokenValidated = context =>
                    //{

                    //     var claims = new List<Claim>
                    //     {
                    //        new Claim(ClaimTypes.Role, "superadmin")
                    //     };
                    //    var appIdentity = new ClaimsIdentity(claims);
                    //    context.Principal.AddIdentity(appIdentity);
                    //    return Task.CompletedTask;
                    //    //return myUserValidationLogic(context.Ticket.Principal);
                    //}
                };
            });

Хотя класс CustomActionFactory определен ниже

      public class CustomClaimsFactory : ClaimAction
    {
        string _ClaimType;
        string _ValueType;
        public CustomClaimsFactory(string claimType, string valueType) : base(claimType, valueType)
        {
            _ClaimType = claimType;
            _ValueType = valueType;
        }
        public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
        {
            identity.AddClaim(new Claim(_ClaimType, _ValueType, issuer));

        }
    }```

Предлагаем использовать класс ClaimAction, вот ссылка. Он также работает для asp net core 3.x

OnTokenValidated имеет метод для добавления нового удостоверения, которое вы создаете с утверждением:

      OnTokenValidated = ctx =>{ ctx.Principal.AddIdentity(myNewClaim); }
Другие вопросы по тегам