ADFS 身份验证期间的间歇性重定向循环
Intermittent redirection loops during ADFS authentication
我正在使用 Owin 配置我的 ASP.NET MVC 5(.NET 4.5、IIS 7/8)应用程序以针对第三方 ADFS 设置进行身份验证:
app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
Wtrealm = Settings.Auth.Wtrealm,
MetadataAddress = Settings.Auth.MetadataAddress
});
我还有一个自定义身份验证过滤器(与 AuthorizeAttribute
结合使用):
public class OwinAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
var user = filterContext.RequestContext.HttpContext.User;
var authenticated = user.Identity.IsAuthenticated;
if (!authenticated)
{
return;
}
/* Redirect to profile setup if not already complete */
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
}
}
这有一半时间工作正常,但有时,在初始登录时,应用程序和 ADFS 登录之间会出现重定向循环。这似乎是特定于会话的(不会同时对所有用户发生)并且一旦发生重定向循环,它似乎会继续发生,直到应用程序池刷新。
当重定向循环发生时,我仍然可以看到(在 Chrome 的网络选项卡中)看起来像是 ADFS 发出的有效令牌。
我很难找出根本原因,但我发现 - 当循环没有发生时,user.Identity
的类型为 ClaimsIdentity
和 IsAuthenticated
是 true
。当它 确实 发生时,IsAuthenticated
是 false
但 user.Identity
是 WindowsIdentity
.
类型
IIS 中的所有身份验证形式(匿名身份验证除外)均已禁用。 IIS Express 未在任何地方使用。
可能是什么原因造成的?
您是否使用会话数据和/或 TempData?我了解它与 cookie 相关。我也有同样的问题。
这是一些more information and a thorough explanation of the cause. The problem can be worked around by forcing Owin to use System.Web's cookie pipeline (from here):
public class SystemWebCookieManager : ICookieManager
{
public string GetRequestCookie(IOwinContext context, string key)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
var cookie = webContext.Request.Cookies[key];
return cookie == null ? null : cookie.Value;
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
bool expiresHasValue = options.Expires.HasValue;
var cookie = new HttpCookie(key, value);
if (domainHasValue)
{
cookie.Domain = options.Domain;
}
if (pathHasValue)
{
cookie.Path = options.Path;
}
if (expiresHasValue)
{
cookie.Expires = options.Expires.Value;
}
if (options.Secure)
{
cookie.Secure = true;
}
if (options.HttpOnly)
{
cookie.HttpOnly = true;
}
webContext.Response.AppendCookie(cookie);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
AppendResponseCookie(
context,
key,
string.Empty,
new CookieOptions
{
Path = options.Path,
Domain = options.Domain,
Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
});
}
}
并连接起来:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// ...
CookieManager = new SystemWebCookieManager()
})
我正在使用 Owin 配置我的 ASP.NET MVC 5(.NET 4.5、IIS 7/8)应用程序以针对第三方 ADFS 设置进行身份验证:
app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
Wtrealm = Settings.Auth.Wtrealm,
MetadataAddress = Settings.Auth.MetadataAddress
});
我还有一个自定义身份验证过滤器(与 AuthorizeAttribute
结合使用):
public class OwinAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
var user = filterContext.RequestContext.HttpContext.User;
var authenticated = user.Identity.IsAuthenticated;
if (!authenticated)
{
return;
}
/* Redirect to profile setup if not already complete */
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
}
}
这有一半时间工作正常,但有时,在初始登录时,应用程序和 ADFS 登录之间会出现重定向循环。这似乎是特定于会话的(不会同时对所有用户发生)并且一旦发生重定向循环,它似乎会继续发生,直到应用程序池刷新。
当重定向循环发生时,我仍然可以看到(在 Chrome 的网络选项卡中)看起来像是 ADFS 发出的有效令牌。
我很难找出根本原因,但我发现 - 当循环没有发生时,user.Identity
的类型为 ClaimsIdentity
和 IsAuthenticated
是 true
。当它 确实 发生时,IsAuthenticated
是 false
但 user.Identity
是 WindowsIdentity
.
IIS 中的所有身份验证形式(匿名身份验证除外)均已禁用。 IIS Express 未在任何地方使用。
可能是什么原因造成的?
您是否使用会话数据和/或 TempData?我了解它与 cookie 相关。我也有同样的问题。
这是一些more information and a thorough explanation of the cause. The problem can be worked around by forcing Owin to use System.Web's cookie pipeline (from here):
public class SystemWebCookieManager : ICookieManager
{
public string GetRequestCookie(IOwinContext context, string key)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
var cookie = webContext.Request.Cookies[key];
return cookie == null ? null : cookie.Value;
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
bool pathHasValue = !string.IsNullOrEmpty(options.Path);
bool expiresHasValue = options.Expires.HasValue;
var cookie = new HttpCookie(key, value);
if (domainHasValue)
{
cookie.Domain = options.Domain;
}
if (pathHasValue)
{
cookie.Path = options.Path;
}
if (expiresHasValue)
{
cookie.Expires = options.Expires.Value;
}
if (options.Secure)
{
cookie.Secure = true;
}
if (options.HttpOnly)
{
cookie.HttpOnly = true;
}
webContext.Response.AppendCookie(cookie);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (options == null)
{
throw new ArgumentNullException("options");
}
AppendResponseCookie(
context,
key,
string.Empty,
new CookieOptions
{
Path = options.Path,
Domain = options.Domain,
Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
});
}
}
并连接起来:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// ...
CookieManager = new SystemWebCookieManager()
})