IdentiyServer4:自动令牌刷新dosn不更新外部令牌

时间:2016-10-26 12:53:23

标签: c# asp.net-core openid-connect identityserver4 idsrv

在过去的几周里,我一直在为我们的一个系统开发一个新的身份提供者。这是我第一次使用IdentityServer和OpenId,并且我已经设法充分利用它,但是我一直在用这个打破一个混凝土墙。

我一直在尝试制作

我们的目标是拥有一个身份提供者(IdentityServer4),我们可以将其用于所有当前和未来的系统。我们希望这样做尽可能简单,因此它只验证用户,并为客户提供名称,profilepicture和电子邮件。

接下来,每个系统都有另一个IdentityServer4服务器,用于处理用户访问权限。这意味着,这将为客户提供角色等。

最后,我们有客户。

我试图说明,从长远来看我们希望拥有什么,但这个问题仅涉及ID。 PROVIDER,SYSTEM A IDSRV和SYSTEM A CLIENT 1。

|---- SYSTEM A CLIENT 1 |----SYSTEM A IDSRV ----|---- SYSTEM A CLIENT 2 | |---- SYSTEM A CLIENT 3 | | | |---- SYSTEM B CLIENT 1 ID. PROVIDER----|----SYSTEM B IDSRV ----|---- SYSTEM B CLIENT 2 | |---- SYSTEM B CLIENT 3 | | | |---- SYSTEM C CLIENT 1 |----SYSTEM C IDSRV ----|---- SYSTEM C CLIENT 2 |---- SYSTEM C CLIENT 3

最初的自动化工作非常完美!

我有什么

ID。提供者 - > SYSTEM A IDSRV的客户端配置

new Client
{
    ClientId = "SystemA",
    ClientSecrets = new List<Secret>
    {
        new Secret("SystemASecret".Sha256())
    },
    AllowedGrantTypes = GrantTypes.Hybrid,
    AllowedScopes = new List<string>
    {
        StandardScopes.OpenId.Name,
        StandardScopes.Profile.Name,
        StandardScopes.Email.Name,
        StandardScopes.OfflineAccess.Name,
    },
    RedirectUris = new List<string>
    {
        "https://localhost:5400/signin-oidc"
    },
    PostLogoutRedirectUris = new List<string>
    {
        "http://localhost:5400"
    },
    RequireConsent = false,

    RefreshTokenUsage = TokenUsage.OneTimeOnly,
    RefreshTokenExpiration = TokenExpiration.Absolute,
    UpdateAccessTokenClaimsOnRefresh = true,

    IdentityTokenLifetime = 30,
    AccessTokenLifetime = 30,
    AuthorizationCodeLifetime = 30,
    AbsoluteRefreshTokenLifetime = 30,
    SlidingRefreshTokenLifetime = 30,
}

SYSTEM A IDSRV - &gt; Startup.cs:

app.UseIdentityServer();

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,
    AutomaticAuthenticate = false,
    AutomaticChallenge = false,

    LoginPath = new PathString("/Account/Login"),
    ReturnUrlParameter = "returnUrl"
});

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
    SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,
    SignOutScheme = IdentityServerConstants.SignoutScheme,

    DisplayName = "ID. PROVIDER",
    Authority = "https://localhost:5200",
    ClientId = "SystemA",
    ClientSecret = "SystemASecret",

    ResponseType = "code id_token",

    Scope =
    {
        "openid",
        "profile",
        "email",
        "offline_access"
    },

    TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "role"
    },

    GetClaimsFromUserInfoEndpoint = true,
    SaveTokens = true,
    UseTokenLifetime = true
});

SYSTEM A IDSRV - &gt; SYSTEM A CLIENT 1的客户端配置:

new Client
{
    ClientId = "SystemAClient1",
    ClientName = "SYSTEM A CLIENT 1",
    AllowedGrantTypes = GrantTypes.Hybrid,

    RequireConsent = false,

    ClientSecrets = new List<Secret>
    {
        new Secret("SystemAClient1Secret".Sha256())
    },
    RedirectUris = new List<string>
    {
        "https://localhost:5500/signin-oidc"
    },
    PostLogoutRedirectUris = new List<string>
    {
        "https://localhost:5500"
    },
    AllowedScopes = new List<string>
    {
        StandardScopes.OpenId.Name,
        StandardScopes.Profile.Name,
        StandardScopes.Email.Name,
        StandardScopes.OfflineAccess.Name,
        StandardScopes.Roles.Name,
        CustomScopes.Custom1.Name,
        CustomScopes.Custom2.Name,
        CustomScopes.Custom3.Name
    },

    RefreshTokenUsage = TokenUsage.OneTimeOnly,
    RefreshTokenExpiration = TokenExpiration.Absolute,
    UpdateAccessTokenClaimsOnRefresh = true,

    IdentityTokenLifetime = 30,
    AccessTokenLifetime = 30,
    AuthorizationCodeLifetime = 30,
    AbsoluteRefreshTokenLifetime = 30,
    SlidingRefreshTokenLifetime = 30
}

* SYSTEM A IDSRV - &gt; AccountController(登录时为ExternalCallback,受IdentityServer示例启发。)

    public async Task<IActionResult> ExternalCallback(string returnUrl)
    {
    //Read external identity from the tempoary cookie
    var tempUser = await HttpContext.Authentication.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
    if (tempUser == null)
        throw new Exception("External authentication error");

    //Get external claims
    var claims = tempUser.Claims.ToList();

    //Extract UserId
    var userIdClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject);
    if (userIdClaim == null)
        throw new Exception("Unknown UserId!");

    //Move the UserId claim and from the claims collection to the UserId-property, and set the name of the external authentication provider
    claims.Remove(userIdClaim);
    var provider = userIdClaim.Issuer;

    //Extract addition custom claims to store them in the database
    var firstnameClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.GivenName);
    if (firstnameClaim == null)
        throw new Exception("Firstname claim missing");

    var lastnameClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.FamilyName);
    if (lastnameClaim == null)
        throw new Exception("Lastname claim missing!");

    var emailClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Email);
    if (emailClaim == null)
        throw new Exception("E-mail claim missing!");

    var pictureClaim = claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Picture);
    if (pictureClaim == null)
        throw new Exception("Picture claim missing!");

    var user = await _userService.FindUserByEmail(emailClaim.Value);

    if (user == null)
        user = new User { Identities = new List<UserIdentity>() };

    user.Email = emailClaim.Value;
    user.Firstname = firstnameClaim.Value;
    user.Lastname = lastnameClaim.Value;
    user.Picture = pictureClaim.Value;

    if (!user.Identities.Any(i => i.Identity == userIdClaim.Value && i.Provider == provider))
        user.Identities.Add(new UserIdentity { Identity = userIdClaim.Value, Provider = provider });

    // Save user and login
    await _userService.SaveUser(user);
    await HttpContext.Authentication.SignInAsync(userIdClaim.Value, emailClaim.Value, provider, claims.ToArray());

    // Delete tempoary cookie used during external authentication
    await HttpContext.Authentication.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

    if (_interaction.IsValidReturnUrl(returnUrl))
        return Redirect(returnUrl);

    return Redirect("~/");
}

SYSTEM A CLIENT 1 - &gt; Startup.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "Cookies",
});

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
    SignInScheme = "Cookies",

    Authority = "https://localhost:5400",

    ClientId = "SystemAClient1",
    ClientSecret = "SystemAClient1Secret",

    ResponseType = "code id_token",
    Scope =
    {
        "openid",
        "profile",
        "email",
        "offline_access"
    },

    GetClaimsFromUserInfoEndpoint = true,
    SaveTokens = true,
    UseTokenLifetime = true,
});

问题

当我在30秒刷新间隔后刷新SYSTEM A CLIENT 1上的页面时,我确实刷新了访问令牌并声明了SYSTEM A IDSRV应该如此。但该调用不会刷新访问令牌和ID上的声明。 PROVIDER。

我错过了什么?

提前感谢您阅读这篇文章,希望能帮到我! :)

TL;博士

当客户端启动访问令牌刷新时,IdentityServer4不会刷新来自外部提供程序的访问令牌。

0 个答案:

没有答案