0

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

坚持声明的正确方法是什么(在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;
    }
}
4

2 回答 2

0
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));

        }
    }```
于 2021-08-16T14:39:26.107 回答
-1

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

OnTokenValidated = ctx =>{ ctx.Principal.AddIdentity(myNewClaim); }
于 2021-08-13T15:27:16.143 回答