客户端cookie滑动时刷新IdentityServer cookie

时间:2018-08-23 18:07:11

标签: asp.net authorization identityserver4

我们有多个应用程序,我们的用户可以通过我们的IdentityServer登录。他们都使用Cookie身份验证来保护网站,并使用令牌来保护其相关API。由于某些网站的功能,Cookie需要滑动才能运行。

引起的问题是,当cookie滑动时,它不会与我们的IdentityServer联系,这意味着服务器上的cookie可能会超时。当用户仅停留在已经使用过的应用程序中时,这很好,但是一旦用户连接到另一个应用程序,它将击中IdentityServer(其cookie超时)并被提示再次登录,尽管在其他应用程序中处于活动状态。 / p>

所以我想发生的事情是,每当客户端cookie滑动时,它仍然会击中IdentityServer,以使其cookie随之滑动。我愿意接受其他建议,但是我自己没有其他想法,并且由于我们的应用程序跨越各种.net平台(WebForms,MVC,Core)和工具集(尤其是Teleelek),因此我尝试提出像这样的通用解决方案。

代码:

IdentityServer cookie

        // Configure auth cookie
        services.AddAuthentication(cookieSettings.CookieName)
                .AddCookie(cookieSettings.CookieName, 
                           options =>
                           {
                               options.ExpireTimeSpan = TimeSpan.FromMinutes(cookieSettings.Expiration); // 4 hours
                               options.SlidingExpiration = cookieSettings.AllowSliding; //true
                           });

客户

public static void ConfigureOAuthForWebForms(this IAppBuilder app, OAuthSettings configuration)
{
    // Use Cookies to Store JWT Token for Web Browsers
    var cookieAuthenticationOptions = new CookieAuthenticationOptions
    {
        AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
        CookieDomain = configuration.CookieDomain,
        CookieName = configuration.CookieName,
        CookieHttpOnly = configuration.CookieHttpOnly,
        ExpireTimeSpan = configuration.AuthTimeout,
        SlidingExpiration = configuration.AllowSlidingAuthTimeout
    };

    app.UseCookieAuthentication(cookieAuthenticationOptions);

    // Turn off the JWT claim type mapping to allow well-known claims (e.g. ‘sub’ and ‘idp’) to flow through
    JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();

    var openIdConnectAuthenticationOptions = new OpenIdConnectAuthenticationOptions
    {
        AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
        Authority = configuration.AuthorizationServerUri,
        ClientId = configuration.Client,
        PostLogoutRedirectUri = configuration.RedirectUri,
        RedirectUri = configuration.RedirectUri,
        ResponseType = configuration.ResponseType,
        Scope = configuration.Scope,
        SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
        UseTokenLifetime = configuration.UseAuthServerLifetime, // false
        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            SecurityTokenValidated = async n =>
            {
                var claimsToExclude = new[] { "aud", "iss", "nbf", "exp", "nonce", "iat", "at_hash", "c_hash", "idp", "amr" };

                var claimsToKeep = n.AuthenticationTicket.Identity.Claims.Where(x => false == claimsToExclude.Contains(x.Type)).ToList();
                claimsToKeep.Add(new Claim(AuthConstants.AuthenticationToken, n.ProtocolMessage.IdToken));

                if (n.ProtocolMessage.AccessToken != null)
                {
                    // Add access_token so we don't need to request it when calling APIs
                    claimsToKeep.Add(new Claim(AuthConstants.AccessToken, n.ProtocolMessage.AccessToken));

                    var userInfoClient = new UserInfoClient(new Uri(n.Options.Authority + "connect/userinfo").ToString());
                    var userInfoResponse = await userInfoClient.GetAsync(n.ProtocolMessage.AccessToken);
                    var userInfoClaims = userInfoResponse.Claims
                        .Where(x => x.Type != "sub") // filter sub since we're already getting it from id_token
                        .Select(x => new Claim(x.Type, x.Value));
                    claimsToKeep.AddRange(userInfoClaims);
                }

                var ci = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType, "name", "role");
                ci.AddClaims(claimsToKeep);

                if (!configuration.UseAuthServerLifetime)
                {
                    n.AuthenticationTicket.Properties.IsPersistent = true;
                    n.AuthenticationTicket.Properties.ExpiresUtc = DateTimeOffset.UtcNow.Add(configuration.AuthTimeout); // 2 hours
                    n.AuthenticationTicket.Properties.AllowRefresh = configuration.AllowSlidingAuthTimeout; // true
                }

                n.AuthenticationTicket = new AuthenticationTicket(ci, n.AuthenticationTicket.Properties);
            },
            RedirectToIdentityProvider = n =>
            {
                if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                    n.ProtocolMessage.IdTokenHint = n.OwinContext.Authentication.User.FindFirst(AuthConstants.AuthenticationToken)?.Value;

                return Task.FromResult(0);
            }
        }
    };

    // Authenticate to Auth Server
    app.UseOpenIdConnectAuthentication(openIdConnectAuthenticationOptions);

    app.UseStageMarker(PipelineStage.Authenticate);
}

2 个答案:

答案 0 :(得分:1)

我只想延长IDP上的会话时长,然后就无需滑动它了。您可以使用max_age参数控制用户是否应该从任何给定的客户端再次进行身份验证。

答案 1 :(得分:0)

对于后代/未来使用,这是使用oidc-client调用Auth服务器并延长超时的延长超时的另一种方法。

1)从here

添加oidc-client.min.js

2)将对新Oidc.UserManager()。signinSilent()的调用添加到document.ready上的母版页上

3)添加一个回调处理程序页面来处理该调用的返回结果

4)将回调页面添加到IdentityServer Clients回发uri

我还没有对这个解决方案进行全面的测试,但是我可以在需要时使其正常运行。但是现在,我可能只会使用@mackie的增加Auth服务器超时的解决方案。