3

我目前使用令人惊叹的 Thinktecture IdentityModel 4.5 设置了一个基于 Web API 的应用程序。

它设置为基于声明的身份验证,接受在 Authorization 标头中发送的基本身份验证凭据。javascript 客户端保存返回的会话令牌并将其用于后续请求,方法是将其包含在Session前面的 Authorization 标头中作为方案。

javascript 客户端还将令牌保存到 cookie 中,以便在窗口关闭并快速重新打开时进行检索,或者在打开新窗口时进行检索,以防止用户必须重新进行身份验证。cookie 被命名为sessionToken,它的值是实际的令牌。

这一切都非常好。

问题是我在应用程序页面上有一个链接,该链接链接到直接地址(/api/controller/id/pdfdocument)并在新窗口中打开它(目标:_blank)。因此,无法在此请求中包含 Authorization 标头。但是,由于会话仍处于活动状态,cookie 会正确传输。

我试图向 AuthenticationConfig.Mappings 集合添加一个映射,以添加对从 cookie 收集令牌的支持,但是我无法获得正确的配置以使其正常工作,并且无法找到任何其他资源在线的。我假设有一些非常简单的东西需要修复。

我的代码:

    private static AuthenticationConfiguration CreateAuthenticationConfiguration()
    {
        var sessionTokenConfiguration = new SessionTokenConfiguration();
        sessionTokenConfiguration.EndpointAddress = "/Authenticate";
        sessionTokenConfiguration.DefaultTokenLifetime = new TimeSpan(1, 0, 0);

        var authenticationConfig = new AuthenticationConfiguration
        {
            ClaimsAuthenticationManager = _authenticationManager,
            RequireSsl = false,
            EnableSessionToken = true,
            SessionToken = sessionTokenConfiguration,
            SendWwwAuthenticateResponseHeaders = false
        };

        var securityTokenHandler = new Thinktecture.IdentityModel.Tokens.Http.BasicAuthenticationWithRoleSecurityTokenHandler(_userService.ValidateUser, _userService.GetRolesForUser);
        securityTokenHandler.RetainPassword = false;
        var realm = "localhost";

        var authorizationMapping = new AuthenticationOptionMapping
        {
            Options = AuthenticationOptions.ForAuthorizationHeader(scheme: "Basic"),
            TokenHandler = new System.IdentityModel.Tokens.SecurityTokenHandlerCollection { securityTokenHandler },
            Scheme = AuthenticationScheme.SchemeAndRealm("Basic", realm)
        };
        authenticationConfig.AddMapping(authorizationMapping);

        var cookieMapping = new AuthenticationOptionMapping
        {
            Options = AuthenticationOptions.ForCookie("sessionToken"),
            TokenHandler = new System.IdentityModel.Tokens.SecurityTokenHandlerCollection { securityTokenHandler },
            Scheme = AuthenticationScheme.SchemeOnly(scheme: "Session")
        };
        authenticationConfig.AddMapping(cookieMapping);

        //authenticationConfig.AddBasicAuthentication(_userService.ValidateUser, _userService.GetRolesForUser);

        return authenticationConfig;
    }

然后像这样应用此配置:

HttpConfiguration config;
var authenticationConfig = CreateAuthenticationConfiguration();
config.MessageHandlers.Add(new AuthenticationHandler(authenticationConfig));

这就是请求标头中 cookie 的样子:

Cookie: sessionToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzNzM2NDA5NjgsImlzcyI6InNlc3Npb24gaXNzdWVyIiwiYXVkIjoiaHR0cDovL3Nlc3Npb24udHQvIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2F1dGhlbnRpY2F0aW9ubWV0aG9kIjoiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2F1dGhlbnRpY2F0aW9ubWV0aG9kL3Bhc3N3b3JkIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9hdXRoZW50aWNhdGlvbmluc3RhbnQiOiIyMDEzLTA3LTEyVDEzOjU2OjA4LjA5N1oiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJBZG1pbmlzdHJhdG9yIiwiSWQiOiIyIn0.UlPeD9HzduQfwHE7NuXi9eMVo40hypi_LBK-f76VYFI; username=a

非常感谢任何帮助!

4

1 回答 1

2

因此,在等待了几分钟并且没有收到任何回复并且迫切需要此功能后,我潜入 Thinktecture IdentityModel 4.5 源代码以查看发生了什么,似乎实际上并不支持此功能。不仅不支持它,而且从外观上看 cookie 映射实际上并没有实现。

我分叉了存储库并进行了一些小的更改以允许此功能: https ://github.com/ibraheemhlaiyil/Thinktecture.IdentityModel.45

并在拉取请求中发送了 Thinktecture 的 Dominick Baier: https ://github.com/thinktecture/Thinktecture.IdentityModel.45/pull/95

Cookie 的使用有其缺点,似乎 Thinktecture 正试图尽可能远离它们,但是我无法为我的问题提出不同的解决方案 - 需要打开新窗口/标签的 javascript 客户端 Web 应用程序并在新窗口/选项卡中维护经过身份验证的会话。

如果要使用此功能,只需CookieName在对象上设置新属性SessionTokenConfiguration。IdentityModel 使用该HeaderName属性来确定要查找哪个标头以获取身份验证数据。同样,如果CookieName设置了该属性,则如果在标头上没有找到身份验证数据,这将确定查找哪个 cookie 名称以获取身份验证数据。

在下面的示例中,如果在Authorization标头上找不到身份验证数据,则会在名为sessionToken的 cookie 上查找身份验证数据。

    private static AuthenticationConfiguration CreateAuthenticationConfiguration()
    {

        var authenticationConfig = new AuthenticationConfiguration
        {
            ClaimsAuthenticationManager = _authenticationManager,
            RequireSsl = false,
            SendWwwAuthenticateResponseHeaders = false,
            EnableSessionToken = true,
            SessionToken = new SessionTokenConfiguration
            {
                EndpointAddress = "/Authenticate",
                DefaultTokenLifetime = new TimeSpan(1, 0, 0),
                HeaderName = "Authorization",
                CookieName = "sessionToken",
                SigningKey = CryptoRandom.CreateRandomKey(32)
            }
        };

        authenticationConfig.AddBasicAuthentication(_userService.ValidateUser, _userService.GetRolesForUser);

        return authenticationConfig;
    }

和以前一样,在您的应用程序启动期间应用此配置:

HttpConfiguration config;
var authenticationConfig = CreateAuthenticationConfiguration();
config.MessageHandlers.Add(new AuthenticationHandler(authenticationConfig));

cookie 身份验证数据与 Authorization 标头中发送的数据具有完全相同的形式,因此如果发送,cookie 应该如下所示:

Cookie: sessionToken=Session eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzNzM2NDA5NjgsImlzcyI6InNlc3Npb24gaXNzdWVyIiwiYXVkIjoiaHR0cDovL3Nlc3Npb24udHQvIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2F1dGhlbnRpY2F0aW9ubWV0aG9kIjoiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2F1dGhlbnRpY2F0aW9ubWV0aG9kL3Bhc3N3b3JkIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9hdXRoZW50aWNhdGlvbmluc3RhbnQiOiIyMDEzLTA3LTEyVDEzOjU2OjA4LjA5N1oiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJBZG1pbmlzdHJhdG9yIiwiSWQiOiIyIn0.UlPeD9HzduQfwHE7NuXi9eMVo40hypi_LBK-f76VYFI

希望有人发现这个有用!

于 2013-08-02T20:21:27.433 回答