【发布时间】:2019-09-11 19:17:09
【问题描述】:
我有一个 ASP.NET 4.6 Web 应用程序,我正在尝试使用 OWIN 添加 OpenId Connect。
我添加了我的 Owin 启动类,一切似乎都配置正确,但我遇到的问题是 ASP 身份/身份验证用户永远不会被创建。我最终陷入了一个无限循环,其中 OpenId 回调页面重定向回原始页面,然后重定向到登录页面等。
这是我的启动课:
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login.aspx"),
ExpireTimeSpan = TimeSpan.FromDays(7)
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = _clientId,
ClientSecret = _clientSecret,
Authority = _authority,
RedirectUri = _redirectUri, // LoginCallback
PostLogoutRedirectUri = "http://localhost:60624/Logout.aspx",
ResponseType = OpenIdConnectResponseType.CodeIdToken,
Scope = "openid profile email",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var tokenClient = new TokenClient($"{_authority}/as/token.oauth2", _clientId, _clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, _redirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
var userInfoClient = new UserInfoClient($"{_authority}/idp/userinfo.openid");
var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
var claims = new List<Claim>(userInfoResponse.Claims)
{
new Claim("id_token", tokenResponse.IdentityToken),
new Claim("access_token", tokenResponse.AccessToken)
};
n.AuthenticationTicket.Identity.AddClaims(claims);
//// create the identity
//var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationType);
//System.Web.HttpContext.Current.GetOwinContext().Authentication.SignIn(new AuthenticationProperties
//{
// IsPersistent = true
//}, identity);
}
}
});
}
这里是 Login.aspx 页面:
protected void Page_Load(object sender, EventArgs e)
{
if (!Request.IsAuthenticated)
{
HttpContext.Current.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = Request["ReturnUrl"] ?? "Default.aspx" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
页面流程是这样的:
1) 请求:http://localhost:60624/Page.aspx 响应:302 - 重定向到 Login.aspx
2) 请求:http://localhost:60624/Login.aspx?ReturnUrl=%2FPage.aspx 响应 302 - 重定向到 https://auth.myprovider.com
在响应标头上设置了一些 cookie:
设置 Cookie:OpenIdConnect.nonce.KIsuj4RUmGKJIynLrkEScxBvGrZzkMo6ylZ%2F4lRknPM%3D=xxxxxxxxx;路径=/;过期=格林威治标准时间 2019 年 4 月 22 日星期一 14:12:00; HttpOnly 设置 Cookie:OpenIdConnect.nonce.KIsuj4RUmGKJIynLrkEScxBvGrZzkMo6ylZ%2F4lRknPM%3D=yyyyyyyyy;过期=格林威治标准时间 2019 年 4 月 22 日星期一 14:12:00;路径=/; HttpOnly
3) Auth 提供者,登录,它 302 重定向到 /LoginCallback
4) 请求:http://localhost:60624/LoginCallback 响应 302 - 重定向到 /Page.aspx
步骤 2 中设置的 Cookie 将在此处清除。
设置 Cookie:OpenIdConnect.nonce.KIsuj4RUmGKJIynLrkEScxBvGrZzkMo6ylZ%2F4lRknPM%3D=;路径=/; expires=周四,1970 年 1 月 1 日 00:00:00 GMT 设置 Cookie:OpenIdConnect.nonce.KIsuj4RUmGKJIynLrkEScxBvGrZzkMo6ylZ%2F4lRknPM%3D=;过期=周四,1970 年 1 月 1 日 00:00:00 GMT;路径=/
5) 返回Page.aspx,用户未通过身份验证;转到第 1 步
我已经进行了一些调试,并且 AuthorizationCodeReceived 在 Startup 上触发,并且后端成功调用了 User Info 端点。我尝试从该通知中调用 System.Web.HttpContext.Current.GetOwinContext().Authentication.SignIn(),但这似乎没有任何作用。
在这一点上,我被困住了。为什么未设置用户身份的身份验证 cookie?似乎这应该自动发生。我应该自己手动创建吗? (How can I manually create a authentication cookie instead of the default method?)
编辑:在查看 @Zaxxon 的回复后,我能够让它工作。 AuthorizationCodeReceived 通知中有两处错误
- 我需要创建 ClaimsIdentity。在我上面提交的原始代码中,我已经注释掉了这一点,但它也是不正确的。
- 我不得不用刚刚创建的新身份替换 AuthenticationTicket。然后将声明添加到这个新身份。
这是工作代码:
ClaimsIdentity identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.GivenName, ClaimTypes.Role);
n.AuthenticationTicket = new AuthenticationTicket(identity, n.AuthenticationTicket.Properties);
n.AuthenticationTicket.Identity.AddClaims(claims);
【问题讨论】:
-
服务器上已有的cookie可能无效或过期。我会使用 IE 并删除所有 cookie 并重试。我认为您遇到了异常,应该在发生异常时退出代码而不是重试。错误 302 看起来像是某种端口转发算法。请参阅:en.wikipedia.org/wiki/List_of_HTTP_status_codes
-
没有错误。 HTTP 302 是此过程中的正常重定向响应,因为它在页面流之间移动。在此过程中,我没有看到任何异常,即使在清除 cookie 之后也是如此。
-
你看到 200 OK 了吗?我怀疑您遇到异常并会添加异常处理程序。还会检查事件查看器以查看是否有任何错误。
-
我没有看到 200 OK,因为用户从未经过身份验证。正如我提到的,在通过身份验证流程之后,它会重复自己,因为在身份验证期间从未设置过 cookie。我应该在 OWIN 进程的哪里添加异常处理程序?
-
您需要使用像 wireshark 或 fiddler 这样的嗅探器,并首先确认您正在发送请求。一旦请求被发送到服务器,服务器应该发回一个状态为 200 OK(或失败状态)的响应。现在根据您的描述,我不确定是否曾经发送过请求。我也无法判断这是安全的(使用 SSL 或 TTLS)还是不安全的。然后我不知道您使用的是 http 1.0(流模式)还是 http 1.1(块模式)。服务器可能没有运行,因此从 cmd.exe 使用 > Netstat -a 并验证端口 60624 上是否有侦听器。
标签: c# owin openid-connect owin-middleware