首页 文章

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

提问于
浏览
2

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

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

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

EDIT

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

1 回答

  • 1

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

    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”进行身份验证/登录 . 我试过了,但是无法让它发挥作用 .

相关问题