【发布时间】:2016-11-24 05:13:43
【问题描述】:
我正在使用 Identityserver3 通过 OpenIDConnect 进行身份验证。我注意到即使用户没有同意,IdentityServer3 也会返回用户的个人资料信息。我不确定这是默认行为还是错误。它发生在我使用 EF 和 AspNetIdentity 配置客户端、范围和用户时。 这就是我配置 IdentityServer 的方式
用户
Properties
UserName: Someusername
Password: SomePassword
Email: user@domain.com
Phone:1234567
Claims:
Country: US
TimeZoneID: CST
范围(openid)
Name: openid
Enabled: true
Type: 0 ( ie. Identity)
客户
AbsoluteRefreshTokenLifeTime: 300
AccessTokenLifeTime: 7200
ClientID: LocalHostMvcClient
Client Name: Local Host Client
Enabled: true
EnableLocalLoging: true
IdentityTokenLifetimne:300
PrefixClientClaims: true
RequireConsent:true
AllowAccessTokenViaBrowser:true
Scopes: openid
请注意,没有添加profile 范围,这意味着客户端无法请求个人资料信息,因此用户也无法同意个人资料信息。用户只能同意身份信息。
我已将客户端配置如下
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44314/identity",
Scope = "openid",
ClientId = "LocalHostMvcClient",
RedirectUri = "http://localhost:34937/",
ResponseType = "id_token token",
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
var nid = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
// get userinfo data
var userInfoClient = new UserInfoClient(
new Uri(n.Options.Authority + "/connect/userinfo"),
n.ProtocolMessage.AccessToken);
var userInfo = await userInfoClient.GetAsync();
userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Item1, ui.Item2)));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
}
}
});
}
我期待 userInfoClient.GetAsync() 只会返回 preferred_username 和 sub 声明。但是它也会返回所有用户的个人资料信息。比如电话号码、电子邮件、国家和时区ID。
我注意到只有当我使用 EF 和 AspNetIdentity 在 SQL 中配置用户、范围和客户端时才会发生这种行为。如果我在内存中配置,我看不到这种情况发生
Update1 (根据 Brock Allen 在下面的回复中的问题)
public class UserService : AspNetIdentityUserService<User, string>
{
public UserService(UserManager userMgr)
: base(userMgr)
{
}
}
public class AspNetIdentityUserService<TUser, TKey> : UserServiceBase
where TUser : class, Microsoft.AspNet.Identity.IUser<TKey>, new()
where TKey : IEquatable<TKey>
{
..
..
..
..
public override async Task GetProfileDataAsync(ProfileDataRequestContext ctx)
{
var subject = ctx.Subject;
var requestedClaimTypes = ctx.RequestedClaimTypes;
if (subject == null) throw new ArgumentNullException("subject");
TKey key = ConvertSubjectToKey(subject.GetSubjectId());
var acct = await userManager.FindByIdAsync(key);
if (acct == null)
{
throw new ArgumentException("Invalid subject identifier");
}
var claims = await GetClaimsFromAccount(acct);
if (requestedClaimTypes != null && requestedClaimTypes.Any())
{
claims = claims.Where(x => requestedClaimTypes.Contains(x.Type));
}
ctx.IssuedClaims = claims;
}
}
更新2
以下修复似乎对我有用。
public override async Task GetProfileDataAsync(ProfileDataRequestContext ctx)
{
var requestedClaimTypes = ctx.RequestedClaimTypes;
if (requestedClaimTypes != null && requestedClaimTypes.Any())
{
var subject = ctx.Subject;
if (subject == null) throw new ArgumentNullException("subject");
TKey key = ConvertSubjectToKey(subject.GetSubjectId());
var acct = await userManager.FindByIdAsync(key);
if (acct == null)
{
throw new ArgumentException("Invalid subject identifier");
}
var claims = await GetClaimsFromAccount(acct);
claims = claims.Where(x => requestedClaimTypes.Contains(x.Type));
ctx.IssuedClaims = claims;
}
}
但是,我还注意到另一个问题。在profile 范围内,即使我将IncludeAllCliamsForUser 设置为true,仍然在GetProfileDataAsync 方法ctx.RequestedClaimTypes 中返回null。
因此,即使客户端请求 profile,UserInfo 端点也不会返回任何声明
要使其正常工作,除了上述修复之外,我还必须将用户声明显式添加到 profile 范围并将 IncludeAllCliamsForUser 设置为 false
【问题讨论】:
标签: identityserver3