【问题标题】:.NET Core 2 / Identity Server 4 - refresh all of the claims.NET Core 2 / Identity Server 4 - 刷新所有声明
【发布时间】:2018-04-29 10:52:27
【问题描述】:

我有一个使用 Identity Server 4 的 .net 核心应用程序,它为应用程序中的授权创建了许多非标准声明。其中一些非标准声明直接影响应用程序的行为方式并由数据库设置。如果用户在 UI 上执行某些操作,我将需要重置这些声明。

所以我的问题是,如果我在https://github.com/IdentityServer/IdentityServer4.Samples/blob/release/Clients/src/MvcHybrid/Controllers/HomeController.cs 处找到更新令牌,使用混合流程会调用用户信息端点以获取更新的声明列表吗?所以或多或少,无需注销并重新登录即可重置登录。还是我需要手动更新 Claims 主体?

我宁愿不必手动更新主体,让 IS4 完成繁重的工作。

编辑

使用上面的代码,我能够刷新令牌,我看到它正在调用 IS4 并重置 IS4 代码中的声明,但它没有获取用户配置文件,它实际上并没有在客户端更新声明。我无法将声明保存在令牌中,因为令牌变得太大而无法注销,因此我在选项上启用了“GetClaimsFromUserInfoEndpoint”。无论如何以编程方式重置用户配置文件?

【问题讨论】:

    标签: c# asp.net identityserver4 asp.net-core-2.0


    【解决方案1】:

    找到了!使用示例代码中的刷新令牌,您需要在对 cookie 进行身份验证之后但在登录 cookie 之前手动调用 UserInfo 端点以获取更新的声明列表。

    var disco = await DiscoveryClient.GetAsync(this.applicationSettings.IdentityServerAuthority);
    if (disco.IsError) throw new Exception(disco.Error);
    
    var userInfoClient = new UserInfoClient(disco.UserInfoEndpoint);
    var tokenClient = new TokenClient(disco.TokenEndpoint, this.applicationSettings.IdentityServerAuthorityClient, this.applicationSettings.IdentityServerAuthorityPassword);
    var rt = await this.httpContext.HttpContext.GetTokenAsync("refresh_token");
    var tokenResult = await tokenClient.RequestRefreshTokenAsync(rt);
    
    if (!tokenResult.IsError)
    {
        var old_id_token = await this.httpContext.HttpContext.GetTokenAsync("id_token");
        var new_access_token = tokenResult.AccessToken;
        var new_refresh_token = tokenResult.RefreshToken;
    
        var tokens = new List<AuthenticationToken>();
        tokens.Add(new AuthenticationToken { Name = OpenIdConnectParameterNames.IdToken, Value = old_id_token });
        tokens.Add(new AuthenticationToken { Name = OpenIdConnectParameterNames.AccessToken, Value = new_access_token });
        tokens.Add(new AuthenticationToken { Name = OpenIdConnectParameterNames.RefreshToken, Value = new_refresh_token });
    
        var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
        tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) });
        var info = await this.httpContext.HttpContext.AuthenticateAsync("Cookies");
        //get the updated user profile (claims)
        var response = await userInfoClient.GetAsync(new_access_token);
        info.Properties.StoreTokens(tokens);
    
        //merge the new claims with the current principal
        var currentIdentity = info.Principal.Identity as ClaimsIdentity;
        var distinctClaimTypes = response.Claims.Select(x => x.Type).Distinct();
        foreach (var claimType in distinctClaimTypes)
        {
            var currentCount = currentIdentity.Claims.Count(x => x.Type == claimType);
            if (currentCount > 0)
            {
                //remove the claims from the current
                var currentClaims = currentIdentity.Claims.Where(x => x.Type == claimType).ToList();
                foreach (var currentClaim in currentClaims)
                {
                    currentIdentity.RemoveClaim(currentClaim);
                }
            }
    
            //add the new claims
            currentIdentity.AddClaims(response.Claims.Where(x => x.Type == claimType));
        }
    
        //update the cookies with the new principal and identity
        await this.httpContext.HttpContext.SignInAsync("Cookies", info.Principal, info.Properties);
    
        return true;
    }
    

    可能还有一种使用“oidc”进行身份验证/登录的方法。我试过了,但无法让它工作。

    【讨论】:

    • 嗨,我正在尝试做一些非常相似的事情,但需要切换“上下文”,例如在每次刷新时更新一个自定义声明。但是除了更新的到期日期之外,刷新令牌似乎没有多大作用。我不知道如何将自定义参数传递给 userInfoClient,因此它从 ProfileService 获得相同的自定义声明。有什么提示吗?谢谢
    • 正是我需要的@RodneyPannell。感谢您抽出宝贵时间发布您学到的知识。
    猜你喜欢
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 2018-10-16
    • 1970-01-01
    • 2017-03-20
    • 2015-05-29
    • 2021-01-17
    • 2019-04-09
    相关资源
    最近更新 更多