如何使用Thinktecture Identity Server3和OpenId实现单点注销,用于多个ASP.NET MVC应用程序的中间件

时间:2016-08-17 22:01:14

标签: identityserver3

我有2个ASP.NET MVC应用程序,我使用OpenID中间件 UseOpenIdConnectAuthentication 对两者进行单点登录。配置如下所述。 SSO效果很好。我从应用程序1登录,然后检查我是否登录到连接到idserver的应用程序2,我可以看到自己已登录。两个客户端应用程序现在都具有相同的id_token和令牌。

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        AuthenticationType = "oidc",
        SignInAsAuthenticationType = "Cookie",
        Authority = "<my-idserver-url>",
        ClientId = "client1",
        RedirectUri = "https://localhost:44360",
        PostLogoutRedirectUri = "https://localhost:44360",                
        ResponseType = "id_token token",

       //scopes from config file
        Scope = ConfigurationManager.AppSettings.Get("Scope"),

        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            SecurityTokenValidated = n =>
            {
                var claims = n.AuthenticationTicket.Identity.Claims;
                var accepted_claims = new[]{"name", "tenant", "email", "sub"};
                var new_claims = claims.Where(x => accepted_claims.Contains(x.Type)).ToList();

                new_claims.Add(new Claim("id_token", n.ProtocolMessage.IdToken));
                new_claims.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));

                var ci = new ClaimsIdentity(new_claims, n.AuthenticationTicket.Identity.AuthenticationType, "email", "role");
                n.AuthenticationTicket = new AuthenticationTicket(ci, n.AuthenticationTicket.Properties);

                return Task.FromResult(0);
            }

单击应用程序中的注销时,在客户端中调用RedirectToIdentityProvider方法时,我将id_token设置为IdTokenHint,如下所示:

RedirectToIdentityProvider = n =>
            {
                if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.LogoutRequest)
                {
                    var user = n.OwinContext.Authentication.User;
                    if (user != null && user.Identity.IsAuthenticated)
                    {
                        var id_token_claim = user.Claims.FirstOrDefault(x => x.Type == "id_token");
                        if (id_token_claim != null)
                        {
                            n.ProtocolMessage.IdTokenHint = id_token_claim.Value;
                        }
                    }
                }
                return Task.FromResult(0);
            }

问题区域&gt;单点注销:

成功案例: 当我从应用程序1注销时,它会重定向到idserver并将我注销并将我重定向回应用程序1.在调试时,我可以看到DefaultViewService的logout方法中的注销消息在这种情况下不为null。这很有效。

失败情景: 问题是当我尝试从应用程序2而不是应用程序1注销时(请记住我从应用程序1登录),它确实将我带到了idserver的注销页面,我可以注销。但它不会重定向回应用程序2并保留在idserver注销页面上。在调试时,我可以看到DefaultViewService的logout方法中的注销消息在这种情况下为null。

可能是因为id_token最初发给了application1?

我错过了什么? 我是否需要处理这种情况并以某种方式获取用户使用的身份服务器中的客户端实际注销(应用程序2)?然后可能会发布一个新的SignoutMessage并为该客户端添加postlogout重定向Url?

或者我错了,这应该自动生效?

更新 一个错误就是尝试将IISExpress localhost上的所有东西都放在不同的端口上,两个客户端(locahost,不同的端口)以某种方式获得相同的id_token和访问令牌,这不应该发生。

迁移到托管不同站点的IIS解决了这个问题,现在应用程序可以获得他们自己的id_token和访问令牌。

我仍然致力于单一退出,探索iFrame方法。

1 个答案:

答案 0 :(得分:0)

我自己一直在努力奋斗几天。谷歌搜索向我指出了你的问题:)

这就是我所做的对我有用的事情(不确定这是否是正确的方法):

在PostLogoutRedirectUris中为每个客户端配置添加了两个Client Uris:

PostLogoutRedirectUris = new List<string>()
{
    "http://localhost:28560/",
    "http://localhost:57311/"
}