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

时间:2017-11-16 02:24:02

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

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

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

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

修改

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

1 个答案:

答案 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;
}

可能有一种方法可以使用&#34; oidc&#34;进行身份验证/登录。同样。我试过了,但是无法让它发挥作用。