.NET Core 2 / Identity Server 4 - 刷新所有声明

3
我有一个.NET Core应用程序,使用Identity Server 4创建了许多非标准声明,以授权应用程序。其中一些非标准声明直接影响应用程序的行为,并由数据库设置。如果用户在UI上执行某些操作,我需要重置这些声明。
那么问题来了,如果我使用混合流程(renew tokens),像这里找到的https://github.com/IdentityServer/IdentityServer4.Samples/blob/release/Clients/src/MvcHybrid/Controllers/HomeController.cs,它会调用用户信息端点以获取更新的声明列表吗?换句话说,重新登录而无需注销并再次登录。还是我需要手动更新Claims principal?
我宁愿IS4做繁重工作,而不必手动更新principal。
编辑:
使用上述代码,我能够刷新令牌,看到它正在调用IS4并重置IS4代码中的声明,但它没有获取用户配置文件,该配置文件实际上未在客户端侧更新声明。我无法保存声明在令牌中,因为令牌变得过于庞大并且需要注销,所以我已启用了选项中的“GetClaimsFromUserInfoEndpoint”选项。是否有编程方式重置UserProfile?
1个回答

2

找到了!使用示例代码中的刷新令牌,您需要在身份验证 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获取相同的自定义声明。有什么提示吗?谢谢。 - Whoever
正是我所需要的@RodneyPannell。感谢您抽出时间发布您所学到的内容。 - mikeo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接