将 ClaimsIdentity 添加到 ClaimsPrincipal - JwtBearer
Add ClaimsIdentity to ClaimsPrincipal - JwtBearer
我的系统包含两个授权步骤(但不是标准方式)。
我的客户端应用程序首先通过登录名和密码连接到服务器(类似于 ApiSecret 和 ApiKey)。
下一步,身份验证后,服务器 returns 具有基本信息(用户名、角色等)的不记名令牌。但是请注意,这个用户就像 ApiClient 而不是活人:)
接下来,应用程序显示登录表单。现在是活人登录的时候了。因此,他将他的凭据传递给 API,后者检查该用户是否可以登录。
这是我遇到问题的地方。直到现在我都认为它会像那样工作:
如果用户可以登录到应用程序,我会创建新的 ClaimsIdentity 并将其添加到 ClaimsPrincipal Identities。
这个想法很好,但行不通:/事实证明,下一个请求不会发送第二个身份信息。我什至知道为什么。因为 ClaimsPrincipal 是基于接收到的不记名令牌创建的。但是这些知识并不能解决我的问题。
我应该如何将新的 ClaimsIdentity 添加到现有的 ClaimsPrincipal 并在请求之间存储此值? (直到用户退出应用程序)
经过大量挖掘和研究,我能够创建一个解决方案 (.Net Core 2)。
您必须在配置服务中添加 Cookie 身份验证,所有这些应该如下所示:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
//standard settings
})
.AddCookie(AuthTypes.CLIENT_AUTHENTICATION_TYPE, cfg =>
{
//cookie settings; the most important is following event:
cfg.Events.OnValidatePrincipal = (CookieValidatePrincipalContext ctx) =>
{
ClaimsPrincipal mainUser = ctx.HttpContext.User; //get ClaimsPrincipal from JwtBearer
ClaimsPrincipal cookieUser = ctx.Principal; //get ClaimsPrincipal read from Cookie
Debug.Assert(mainUser.Identities.Count() == 1);
//now we have to add ClaimsIdentity to main ClaimsPrincipal (from JwtBearer). We add only those absent in main ClaimsPrincipal (here is simplified solution)
var claimsToAdd = cookieUser.Identities.Where(id => id.AuthenticationType != mainUser.Identities.ElementAt(0).AuthenticationType);
mainUser.AddIdentities(claimsToAdd);
return Task.CompletedTask;
};
}
);
AuthTypes.CLIENT_AUTHENTICATION_TYPE - 它只是带有您的身份验证类型名称的字符串。
接下来我们必须稍后在 ConfigureServices(基本配置)中配置默认策略过滤器:
services.AddMvc(config =>
{
var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, AuthTypes.CLIENT_AUTHENTICATION_TYPE })
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(defaultPolicy));
});
这里重要的是在 AuthorizationPolicyBuilder 中传递这个数组。
现在授权将考虑 JwtBearer,但也会读取 cookie。
以及现在如何设置 cookie。这可以是额外的登录过程(您在控制器级别进行):
var authProps = new AuthenticationProperties
{
IsPersistent = true,
IssuedUtc = DateTimeOffset.Now
};
await HttpContext.SignInAsync(AuthTypes.CLIENT_AUTHENTICATION_TYPE, User, authProps);
User 这里只是带有附加 ClaimsIdentities 的 ClaimsPrincipal。
这就是所有人:)
我的系统包含两个授权步骤(但不是标准方式)。
我的客户端应用程序首先通过登录名和密码连接到服务器(类似于 ApiSecret 和 ApiKey)。
下一步,身份验证后,服务器 returns 具有基本信息(用户名、角色等)的不记名令牌。但是请注意,这个用户就像 ApiClient 而不是活人:)
接下来,应用程序显示登录表单。现在是活人登录的时候了。因此,他将他的凭据传递给 API,后者检查该用户是否可以登录。
这是我遇到问题的地方。直到现在我都认为它会像那样工作:
如果用户可以登录到应用程序,我会创建新的 ClaimsIdentity 并将其添加到 ClaimsPrincipal Identities。
这个想法很好,但行不通:/事实证明,下一个请求不会发送第二个身份信息。我什至知道为什么。因为 ClaimsPrincipal 是基于接收到的不记名令牌创建的。但是这些知识并不能解决我的问题。
我应该如何将新的 ClaimsIdentity 添加到现有的 ClaimsPrincipal 并在请求之间存储此值? (直到用户退出应用程序)
经过大量挖掘和研究,我能够创建一个解决方案 (.Net Core 2)。 您必须在配置服务中添加 Cookie 身份验证,所有这些应该如下所示:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(cfg =>
{
//standard settings
})
.AddCookie(AuthTypes.CLIENT_AUTHENTICATION_TYPE, cfg =>
{
//cookie settings; the most important is following event:
cfg.Events.OnValidatePrincipal = (CookieValidatePrincipalContext ctx) =>
{
ClaimsPrincipal mainUser = ctx.HttpContext.User; //get ClaimsPrincipal from JwtBearer
ClaimsPrincipal cookieUser = ctx.Principal; //get ClaimsPrincipal read from Cookie
Debug.Assert(mainUser.Identities.Count() == 1);
//now we have to add ClaimsIdentity to main ClaimsPrincipal (from JwtBearer). We add only those absent in main ClaimsPrincipal (here is simplified solution)
var claimsToAdd = cookieUser.Identities.Where(id => id.AuthenticationType != mainUser.Identities.ElementAt(0).AuthenticationType);
mainUser.AddIdentities(claimsToAdd);
return Task.CompletedTask;
};
}
);
AuthTypes.CLIENT_AUTHENTICATION_TYPE - 它只是带有您的身份验证类型名称的字符串。
接下来我们必须稍后在 ConfigureServices(基本配置)中配置默认策略过滤器:
services.AddMvc(config =>
{
var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, AuthTypes.CLIENT_AUTHENTICATION_TYPE })
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(defaultPolicy));
});
这里重要的是在 AuthorizationPolicyBuilder 中传递这个数组。
现在授权将考虑 JwtBearer,但也会读取 cookie。
以及现在如何设置 cookie。这可以是额外的登录过程(您在控制器级别进行):
var authProps = new AuthenticationProperties
{
IsPersistent = true,
IssuedUtc = DateTimeOffset.Now
};
await HttpContext.SignInAsync(AuthTypes.CLIENT_AUTHENTICATION_TYPE, User, authProps);
User 这里只是带有附加 ClaimsIdentities 的 ClaimsPrincipal。 这就是所有人:)