声明的状态管理如何在 Blazor Server 中工作?
Posted
技术标签:
【中文标题】声明的状态管理如何在 Blazor Server 中工作?【英文标题】:How State management of claims work in Blazor Server? 【发布时间】:2021-10-16 14:07:44 【问题描述】:我已经为身份验证代码流实现了身份服务器。
坚持声明的正确方法是什么(在
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;
【问题讨论】:
【参考方案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以上是关于声明的状态管理如何在 Blazor Server 中工作?的主要内容,如果未能解决你的问题,请参考以下文章