我目前使用神奇的Thinktecture IdentityModel 4.5设置了基于Web API的应用程序。
它设置为基于声明的身份验证,接受授权标头上发送的基本身份验证凭据。 javascript客户端保存返回的会话令牌,并将其用于后续请求,方法是将其包含在以会话作为方案的Authorization标头中。
javascript客户端还将令牌保存到cookie,以便在窗口关闭并快速重新打开时进行检索,或者在打开新窗口时防止用户重新进行身份验证。该cookie名为 sessionToken ,它的值是实际令牌。
一切都运作良好。
问题是我在应用页面上有一个链接到直接地址(/ api / controller / id / pdfdocument)的链接,并在新窗口中打开它(target:_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
最值得赞赏的任何帮助!
答案 0 :(得分: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
希望有人发现这有用!