【问题标题】:IdentityServer3 returns user profile information without user's consentIdentityServer3 未经用户同意返回用户个人资料信息
【发布时间】: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_usernamesub 声明。但是它也会返回所有用户的个人资料信息。比如电话号码、电子邮件、国家和时区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


    【解决方案1】:

    如果您的用户服务实现的GetProfileData 不遵守RequestedClaimTypes 上下文参数,那么这就是泄漏的来源。也许这就是问题所在?

    【讨论】:

    • https://identityserver.github.io/Documentation/docsv2/endpoints/userinfo.html UserInfo 端点的文档说“UserInfo 端点可用于检索有关主题的身份信息。它需要至少具有 'openid' 范围的有效访问令牌”。跨度>
    • 请看上面的update1,这是当前的实现。看起来如果requestedClaimTypes 为空,那么它会返回所有声明..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-13
    • 2018-12-06
    • 2018-04-28
    • 1970-01-01
    相关资源
    最近更新 更多