在对IdentityServer4 Quickstart sample solution(特别是8_AspNetIdentity示例)进行一些调整之后,我遇到了一些问题。
在开始我之前,我不确定我所尝试执行的操作是否受支持,或者我做错了。
此示例解决方案包含与我的问题有关的以下项目:
我要做的是将API项目合并到MVCClient中,以便MVCClient既可以使用OIDC对其MVC网站中的用户进行身份验证,也可以使用承载身份验证来对ResourceOwnerClient进行身份验证。
我对MVCClient的Startup.cs进行了以下更改:
将services.AddMvc();
更改为:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder(new[]
{
JwtBearerDefaults.AuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme,
"oidc"
})
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
在services.AddAuthentication()
中添加了JWT承载选项:
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.Audience = "api1";
})
现在从技术上讲这确实可行,因为ResourceOwnerClient和MVC用户都可以通过MVCClient成功进行身份验证。但是,我有一个警告:
当我从MVC端向用户进行身份验证时,我注意到当前用户中有两个身份。在声明等方面,两者都是相同的。只有当我在MVCClient中放置一个断点时,才会发生这种情况,在IdentityServer上只有一个标识。
在IdentityServer上,我注册了一个UserClaimsPrincipalFactory,它将我自己的自定义声明添加到ClaimsIdentity。在IdentityServer上的两个身份中,我可以看到重复的声明。因此,我看到两个具有四个自定义声明的身份,而不是具有两个自定义声明的身份。我的UserClaimsPrincipalFactory中的CreateAsync方法也因单次登录而被点击了5次。
尽管这种行为很奇怪,但似乎没有任何负面影响。但这仅是我正在构建的大型应用程序的概念证明,而且我担心将来会因此而遇到问题。
如果有人以前曾尝试过这种事情,或者知道为什么会发生这种情况,我们将不胜感激。
答案 0 :(得分:3)
尽管这种设计应该不会发生任何不好的事情,但我会彻底重做。为什么?因为您正在混合Client
和ApiResource
,所以它们在逻辑上应该分开。 Client
是一种应用,某些用户与之交互的东西,即使它是无头的(即自动化服务); ApiResource
由提供给客户端的资源组成,因此没有用户可以直接与其交互。
您可以添加针对IdentityServer的两种身份验证,一种作为API(将其添加为JwtBearer
),另一种作为客户端(并将其添加为Cookies
)。然后,您可以根据操作/控制器的功能使用[Authorize(AuthenticationSchemes = "JwtBearer")]
和= "Cookies"
。
抛开这些,问题在于您的应用程序在MVC端获得了一个Identity,在API端获得了一个Identity,因为它无法告诉您想要哪个。
就这样,您便有了一个想法,这就是我的带有ASP.NET Core Identtiy的IdentityServer的外观,您可以在其中使用UI对其进行登录,还可以使用JwtToken访问REST端点:
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = Configuration["IdentityServerUrl"];
options.ApiName = Configuration["ApiName"];
options.RequireHttpsMetadata = false;
})
.AddCookie(IdentityConstants.ApplicationScheme, o =>
{
o.LoginPath = new PathString("/Account/Login");
o.Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
};
})
.AddCookie(IdentityConstants.ExternalScheme, o =>
{
o.Cookie.Name = IdentityConstants.ExternalScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes(5.0);
})
.AddCookie(IdentityConstants.TwoFactorRememberMeScheme, o =>
{
o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme;
})
.AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
{
o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
o.ExpireTimeSpan = TimeSpan.FromMinutes(5.0);
});