第一次发帖,请温柔一点! :)
我正在为 Office 365 开发 MVC .NET 5 Web 应用程序,并使用 OpenIDConnect 框架。我已设置 OWIN (3) 和 ADAL(2) 以及我的 Azure AD 应用程序。没有用户操作的登录,家庭 Controller 附加了 [Authorize] 属性,强制立即登录重定向到 Azure AD。我没有在任何授权属性中使用角色。
问题:我可以成功登录我的应用程序 - 一次!第一次登录后,我关闭浏览器(或在另一台计算机上打开新浏览器),然后再次点击该应用程序。它将我重定向到我登录的 Azure AD 登录屏幕,然后它不断在应用程序和 Azure 之间重定向,直到我收到臭名昭著的 400 header 到长问题。看看 cookies 店,我发现里面充满了随机数。我检查了缓存(Vittorio 的 EFADALCache 配方,尽管发现此问题时我正在使用 TokenCache.DefaultShared),它有数百行缓存数据(成功登录后仅生成一行)。
我可以看到,当通过输出窗口发生重定向时,每次往返都会生成一个新的访问和刷新 token :
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache
Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52: - TokenCache: Deserialized 1 items to token cache.
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: - TokenCache: Deserialized 1 items to token cache.
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache...
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache...
Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache
iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache
Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenHandlerBase: === Token Acquisition finished successfully. An access token was retuned:
Access Token Hash: PN5HoBHPlhhHIf1lxZhEWb4B4Hli69UKgcle0w7ssvo=
Refresh Token Hash: 3xmypXCO6MIMS9qUV+37uPD4kPip9WDH6Ex29GdWL88=
Expiration Time: 31/07/2015 13:31:51 +00:00
User Hash: GAWUtY8c4EKcJnsHrO6NOzwcQDMW64z5BNOvVIl1vAI=
当问题发生时,我的 OpenIdConnectAuthenticationOptions 中的 AuthorizationCodeReceived 通知会被触发,所以我知道 Azure 认为登录成功(否则不会重定向回应用程序):
private static void PrepO365Auth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
//Configure OpenIDConnect, register callbacks for OpenIDConnect Notifications
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigHelper.ClientId,
Authority = authority,
PostLogoutRedirectUri = "https://localhost:44300/Account/SignedOut",
RedirectUri = "https://localhost:44300/",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = (context) =>
{
ClientCredential credential = new ClientCredential(ConfigHelper.ClientId, ConfigHelper.AppKey);
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(authority, new EFADALTokenCache(signedInUserID)); // TokenCache.DefaultShared Probably need a persistent token cache to handle app restarts etc
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigHelper.GraphResourceId);
return Task.FromResult(0);
},
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error/ShowError?signIn=true&errorMessage=" + context.Exception.Message);
return Task.FromResult(0);
}
}
});
}
}
我已经(在发现问题之后)用我自己的 Auth 属性(继承自 AuthorizeAttribute)替换了 Authorized 属性,这样我就可以尝试进入 Authorize 代码并查看发生了什么。我从 MVC 5 源代码的版本 5 构建了一个 PDB 文件,但所发生的只是它跳回我自己的代码:(话虽这么说,我已经覆盖了我可以覆盖的内容,并发现 filterContext .HttpContext.User.Identity.IsAuthenticated 为 false,这是有道理的,因为这会导致重定向回 Azure 登录。
所以,我知道:
- Azure 正在接受我的登录并返回相关 token
- 第二次登录时,在 OnAuthorization 之前,filterContext.HttpContext.User.Identity.IsAuthenticated 返回 false
- 我的 Azure 应用程序配置很好,否则根本无法进行身份验证
我认为:
- MVC 身份设置中有一些错误。 Azure 工作正常,否则根本无法进行身份验证。
- 这不是 Cookie 问题,因为如果您在另一台计算机上进行第二次登录,就会出现问题
很抱歉,这有点啰嗦,但是有很多这样的无限重定向问题,我需要解释一下为什么我的情况有所不同!
我正在寻找的(如果不是答案!)是插入我如何进一步调试的正确方向。
感谢您提供的任何帮助!
安迪
最佳答案
已经为感兴趣的人找到了答案。这是 Katana 中的一个已知错误,其中 Katana cookie 管理器和 ASP .NET cookie 管理器发生冲突并覆盖彼此的 cookie。完整的详细信息和解决方法在这里:
下面显示的 SystemWebCookieManager 现在可以在 Microsoft.Owin.Host.SystemWeb 中找到Nuget 包。
添加 CodePlex 死亡时的代码:
//stick this in public void ConfigureAuth(IAppBuilder app)
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// ...
CookieManager = new SystemWebCookieManager()
});
//And create this class elsewhere:
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),
});
}
}
我也总结了它的要点:https://gist.github.com/irwinwilliams/823f43ef8a5e8019a95874049dbb8b00
关于asp.net-mvc - 第一次成功登录后第二次登录导致无限重定向循环 MVC .NET 5 OWIN ADAL OpenIDConnect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31747008/