在找到解决方案之前,我在同一个问题上苦苦挣扎了几天。回答您的问题:是的,只要您:
- 在您的请求中包含
profile 或 email 范围,并且
- 在 Azure 门户 Active Directory 部分中配置您的应用程序,以在 委派权限 下包含登录和读取用户配置文件。
请注意,电子邮件地址可能不会在 email 声明中返回:在我的情况下(一旦我让它工作)它会在 name 声明中返回。
但是,根本没有得到电子邮件地址可能是由以下问题之一引起的:
没有与 Azure AD 帐户关联的电子邮件地址
根据Scopes, permissions, and consent in the Azure Active Directory v2.0 endpoint 的本指南,即使您包含email 范围,您也可能无法回复电子邮件地址:
仅当电子邮件地址与用户帐户相关联时,email 声明才会包含在令牌中,但情况并非总是如此。如果它使用email 范围,您的应用应该准备好处理令牌中不存在email 声明的情况。
如果您收到其他与个人资料相关的声明(例如 given_name 和 family_name),这可能就是问题所在。
中间件丢弃的声明
这就是我的原因。我没有收到任何与个人资料相关的声明(名字、姓氏、用户名、电子邮件等)。
在我的例子中,身份处理堆栈如下所示:
问题出在 IdentityServer3.AspNetIdentity AspNetIdentityUserService 类中:InstantiateNewUserFromExternalProviderAsync() method looks like this:
protected virtual Task<TUser> InstantiateNewUserFromExternalProviderAsync(
string provider,
string providerId,
IEnumerable<Claim> claims)
{
var user = new TUser() { UserName = Guid.NewGuid().ToString("N") };
return Task.FromResult(user);
}
注意它会传入一个声明集合然后忽略它。我的解决方案是创建一个派生自此的类并将该方法重写为如下所示:
protected override Task<TUser> InstantiateNewUserFromExternalProviderAsync(
string provider,
string providerId,
IEnumerable<Claim> claims)
{
var user = new TUser
{
UserName = Guid.NewGuid().ToString("N"),
Claims = claims
};
return Task.FromResult(user);
}
我不确切知道您正在使用什么中间件组件,但很容易看到从您的外部提供商返回的原始声明;这至少会告诉您他们恢复正常,并且问题出在您的中间件的某个地方。只需将 Notifications 属性添加到您的 OpenIdConnectAuthenticationOptions 对象,如下所示:
// Configure Azure AD as a provider
var azureAdOptions = new OpenIdConnectAuthenticationOptions
{
AuthenticationType = Constants.Azure.AuthenticationType,
Caption = Resources.AzureSignInCaption,
Scope = Constants.Azure.Scopes,
ClientId = Config.Azure.ClientId,
Authority = Constants.Azure.AuthenticationRootUri,
PostLogoutRedirectUri = Config.Identity.RedirectUri,
RedirectUri = Config.Azure.PostSignInRedirectUri,
AuthenticationMode = AuthenticationMode.Passive,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = context =>
{
// Log all the claims returned by Azure AD
var claims = context.AuthenticationTicket.Identity.Claims;
foreach (var claim in claims)
{
Log.Debug("{0} = {1}", claim.Type, claim.Value);
}
return null;
}
},
SignInAsAuthenticationType = signInAsType // this MUST come after TokenValidationParameters
};
app.UseOpenIdConnectAuthentication(azureAdOptions);
另见