我们正在将新的.net核心Web应用程序添加到现有环境中,其中心是用于身份验证的Identity Server 2。创建新应用程序时,我无法使用现有的身份验证。
目标是新应用中的每个页面都需要登录用户。新应用程序有一些用户表,但不应该要求默认的Identity数据库(AspNetUsers等),也不需要自己的登录对话框(也不需要密码恢复等)。
为此,我将以下内容添加到ConfigureServices()中的Startup.cs文件中:
01:services.AddTransient<IUserStore<ApplicationUser>, E360UserStore<ApplicationUser>>();
02:services.AddTransient<IRoleStore<ApplicationRole<string>>, E360RoleStore<ApplicationRole<string>>>();
03:
04:var authenticationConfigSection = Configuration.GetSection("Authentication");
05:
06:services.AddAuthentication(/*"WsFederation"*/)
07: .AddWsFederation(authenticationScheme: "WsFederation",
08: displayName: "Single Signin",
09: configureOptions: options =>
10: {
11: // MetadataAddress represents the Identity Server instance used to authenticate users.
12: options.MetadataAddress = authenticationConfigSection.GetValue<string>("MetadataAddress");
13:
14: // Wtrealm is the app's relying party identifier in the IS instance.
15: options.Wtrealm = authenticationConfigSection.GetValue<string>("Wtrealm");
16:
17: //options.SignInScheme = "WsFederation";
18: });
19:
20:services.AddMvc(config =>
21: {
22: var policy = new AuthorizationPolicyBuilder(/*"WsFederation"*/)
23: .RequireAuthenticatedUser()
24: .Build();
25:
26: config.Filters.Add(new AuthorizeFilter(policy));
28: })
29: .AddJsonOptions(o => o.SerializerSettings.ContractResolver = new DefaultContractResolver())
30: .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
这会产生错误,“未指定authenticationScheme,并且未找到DefaultChallengeScheme。”所以,我尝试取消注释三个“WsFederation”字符串,一次一个。
我首先尝试取消注释最后一个:
22:var policy = new AuthorizationPolicyBuilder("WsFederation")
23: .RequireAuthenticatedUser()
24: .Build();
这会产生类似但不同的错误,“未指定authenticationScheme,并且未找到DefaultAuthenticateScheme。”
如果我取消注释其他任何一行(或两者):
06:services.AddAuthentication("WsFederation")
17:options.SignInScheme = "WsFederation";
这会产生错误,“无法将远程身份验证处理程序的SignInScheme设置为自身。如果未显式设置,则使用AuthenticationOptions.DefaultSignInScheme或DefaultScheme。”
如果我为“正常”身份验证配置应用程序,如下所示:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
然后我得到一个登录对话框,右边有一个标记为“Single Signin”的按钮,工作得很好。 WsFederation登录的声明映射到在生成的Identity数据库中手动创建的用户。
我在新模型中使用E360UserStore和E360RoleStore的意图是在FindByIdAsync()中映射到IdentityUser(我无法测试这个):
public class ApplicationUser : IdentityUser
{
public User User { get; set; }
public ApplicationUser(User user)
{
base.Id = User.IdentityGuid.ToString("D");
base.Email = user.Person.EmailAddress;
base.NormalizedEmail = user.Person.EmailAddress.ToLowerInvariant();
base.UserName = user.Username;
base.NormalizedUserName = user.Username.ToLowerInvariant();
base.EmailConfirmed = true;
User = user;
}
}
我似乎无法找到删除“默认”登录的秘密酱,而是自动重定向到Identity Server登录。
谢谢阅读!
更新:
@Rytmis建议我缺少的是定义表示该应用程序已“登录”的cookie,这是一个很好的观察,但我仍然缺少一篇文章,因为我不明白我是如何离开WS-Fed的到cookie身份验证(以识别当前用户)。我更改了我的ConfigureServices代码,如下所示,这确实导致程序立即重定向到身份服务器,这是完美的,登录后它重定向回ws-fed端点,然后重定向回初始页面。这一切都是好消息,但初始页面仍然没有看到用户登录。 cookie已创建,但我不知道登录是如何,何地或是否从ws-fed转换为cookie?我定义了自定义IUserStore和IRoleStore类,但这些类没有被使用甚至实例化。
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddWsFederation(authenticationScheme: "WsFederation",
displayName: "Single Signin",
configureOptions: options =>
{
// MetadataAddress represents the Identity Server instance used to authenticate users.
options.MetadataAddress = authenticationConfigSection.GetValue<string>("MetadataAddress");
// Wtrealm is the app's relying party identifier in the IS instance.
options.Wtrealm = authenticationConfigSection.GetValue<string>("Wtrealm");
//options.SignInScheme = "WsFederation";
})
.AddCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.None;
options.Cookie.Name = "AuthCookie";
options.AccessDeniedPath = "/error/accessdenied";
});
services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
services.AddTransient<IUserStore<ApplicationUser>, MyUserStore<ApplicationUser>>();
services.AddTransient<IRoleStore<ApplicationRole<string>>, MyRoleStore<ApplicationRole<string>>>();
远程身份验证的事情是你必须在本地存储一些东西,除非你想对每个请求执行远程身份验证重定向 - 没有人这样做。
除了远程方案之外,您还需要指定一个本地身份验证方案,该方案将用于存储远程身份验证的结果。这通常通过添加Cookie身份验证处理程序并将其用作SignInScheme来完成。