【问题标题】:How State management of claims work in Blazor Server?声明的状态管理如何在 Blazor Server 中工作?
【发布时间】:2021-10-16 14:07:44
【问题描述】:

我已经为身份验证代码流实现了身份服务器。

坚持声明的正确方法是什么(在OnTicketReceivedOnTicketValidated 中,如下所示),以便在后续调用中 到 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;
    }
}

【问题讨论】:

    标签: c# .net-core identityserver4 openid-connect duende-identity-server


    【解决方案1】:
    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));
    
            }
        }```
    

    【讨论】:

      【解决方案2】:

      OnTokenValidated 有一种方法可以添加您使用声明创建的新身份:

      OnTokenValidated = ctx =>{ ctx.Principal.AddIdentity(myNewClaim); }
      

      【讨论】:

      • 请问我们如何在调用服务器时将其取回?
      • 在 OnTokenValidated 回调中添加声明后,声明将在身份用户下可用。
      • 很抱歉,Identity User 没有声明。这是问题的目标。
      • @Abhijeet,我猜你已经关注了this link,你可以尝试添加 IdentityResource
      猜你喜欢
      • 2021-08-02
      • 1970-01-01
      • 2020-11-29
      • 2015-03-22
      • 2021-08-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-17
      • 1970-01-01
      相关资源
      最近更新 更多