我们使用 Ping Federate 来保护两个 Web 服务器(都是 IIS,并且都使用 IIS 集成套件或 Ping 的 opentoken 模块进行保护)。一台服务器托管 WEB API 应用程序,另一台服务器托管网页。 Web API 应用程序已启用 CORS。
网页使用 json 数据向 API 服务器发出 Ajax post 请求。这会导致浏览器发起预检选项请求。在 API 服务器上,Ping 模块会拦截此不包含凭据的请求(规范规定预检选项请求不应包含凭据),并在 Web API 代码应该返回 200 时在处理该请求之前返回 302 重定向。 .
我当前唯一的猜测是制作一个处理选项请求的自定义模块并将其安装在 opentoken 模块之前。还有其他可能/更好的解决方案吗?
最佳答案
我没有等待 PING,而是在其 .NET 集成套件/代理之上放置了 IAuthorizationFilter。像这样的自定义过滤器的好处是您可以更好地控制 API 端点的安全要求。
在编写过滤器时,我使用了以下引用文献:
- http://www.asp.net/web-api/overview/security/authentication-filters
https://msdn.microsoft.com/en-us/magazine/dn781361.aspx
使用开放 token ; 使用 PF.SAML.Result; 使用系统; 使用 System.Collections.Generic; 使用系统配置; 使用 System.Linq; 使用 System.Net.Http; 使用 System.Net.Http.Headers; 使用 System.Security.Claims; 使用系统文本; 使用系统线程; 使用 System.Threading.Tasks; 使用 System.Web.Http.Filters;
命名空间 PF.SAML.Filters { 公共(public)类 PingAuthenticationAttribute :IAuthenticationFilter { 公共(public) bool AllowMultiple { 获取{ 返回 false; } }
// http://www.asp.net/web-api/overview/security/authentication-filters // https://msdn.microsoft.com/en-us/magazine/dn781361.aspx public async Task AuthenticateAsync( HttpAuthenticationContext context, CancellationToken cancellationToken ) { await Task.Run( () => { /* * Look for credentials in the request. * If there are no credentials, do nothing and return (no-op). * If there are credentials but the filter does not recognize the authentication scheme, do nothing and return (no-op). Another filter in the pipeline might understand the scheme. * If there are credentials that the filter understands, try to authenticate them. * If the credentials are bad, return 401 by setting context.ErrorResult. * If the credentials are valid, create an IPrincipal and set context.Principal. */ var opentoken = context.Request.Headers.GetCookies() .SelectMany( c => c.Cookies ) .Where( c => c.Name == "opentoken" ) .FirstOrDefault(); if( opentoken == null ) return; var userInfo = getOpenToken( opentoken.Value ); if( userInfo == null ) { context.ErrorResult = new AuthenticationFailureResult( "Invalid Token", context.Request ); return; } var claims = new List<Claim>(); foreach( var item in userInfo ) { foreach( var value in userInfo[item.Key] ) { claims.Add( new Claim( item.Key, value ) ); } } var id = new ClaimsIdentity( claims, "opentoken" ); var principle = new ClaimsPrincipal( new[] { id } ); context.Principal = principle; } ); } public async Task ChallengeAsync( HttpAuthenticationChallengeContext context, CancellationToken cancellationToken ) { await Task.Run( () => { var challenge = new AuthenticationHeaderValue( "SAML" ); context.Result = new AddChallengeOnUnauthorizedResult( challenge, context.Result ); } ); } private MultiStringDictionary getOpenToken( string token ) { MultiStringDictionary attributes = null; Configuration.Agent agentConfig = (Configuration.Agent) ConfigurationManager.GetSection( "pfConfigurationGroup/agentConfiguration" ); AgentConfiguration config = new AgentConfiguration { CookieDomain = agentConfig.CookieDomain, CookiePath = agentConfig.CookiePath, NotBeforeTolerance = agentConfig.NotBeforeTolerance, ObfuscatePassword = agentConfig.ObfuscatePassword, RenewUntilLifetime = agentConfig.RenewUntilLifetime, SecureCookie = agentConfig.SecureCookie, SessionCookie = agentConfig.SessionCookie, TokenLifetime = agentConfig.TokenLifetime, TokenName = agentConfig.TokenName, UseCookie = agentConfig.UseCookie, UseSunJCE = agentConfig.UseSunJCE, UseVerboseErrorMessages = agentConfig.UseVerboseErrorMessages }; var str = ( config.ObfuscatePassword ? Encoding.UTF8.GetString( Obfuscator.Deobfuscate( agentConfig.Password ) ) : Encoding.ASCII.GetString( Convert.FromBase64String( agentConfig.Password ) ) ); config.SetPassword( str, Token.CipherSuite.AES_128_CBC ); // TODO: Check for token expiration Agent agent = new Agent( config ); attributes = agent.ReadTokenMultiStringDictionary( token ); return attributes; } }
}
关于javascript - Pingfederate opentoken 模块 CORS 请求返回 302 而不是 200,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36658253/