Luc*_*cia 5 asp.net webforms owin katana openid-connect
我有一个 WebForms 应用程序(不是 MVC,不是 WebApi),我正在将其移植到 OpenID Connect 外部身份验证(.net 4.7.2,最新的 OWIN NuGet 包)。此 Web 应用程序使用基于角色的授权,以防止未经授权的用户访问应用程序的某些部分。角色通过 OIDC 声明提供,并在 Web 应用程序中指定为web.config授权条目。
主要流程是这样的:当用户未经身份验证并且用户在其 ClaimsIdentity 中具有适当的角色时,应用程序会正确地将用户重定向到 OIDC 提供商。
当用户登录但不具备访问角色限制区域所需的角色时,就会出现此问题。在这种情况下,UrlAuthorizationModule返回 401 Unauthorized 错误(不应该是 403 Forbidden 吗?!),这会触发 OIDC 质询,该质询会发送到 OIDC 提供商,该提供商返回具有相同声明的同一用户,这会触发另一个401,用户会经历无限的重定向循环。
我可以检测通知中的条件RedirectToIdentityProvider并使用该Response.Redirect方法向用户呈现错误消息,但这会导致 302 > 403 错误序列并更改页面的浏览器 URL 403.aspx。我宁愿重写响应并保留当前 URL,但我不知道如何实现(检查 Startup.cs 代码片段内的 * 标记行)。
你有什么想法?
相关 Startup.cs 片段:
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions() { });
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions {
ClientId = ClientId,
ClientSecret = ClientSecret,
Authority = Authority,
Scope = Scopes,
TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = ClaimTypes.NameIdentifier,
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
// Store the ID Token in the auth ticket to be able to remote logout
if (n.ProtocolMessage.IdToken != null)
{
var idTokenClaim = new Claim("id_token", n.ProtocolMessage.IdToken, ClaimValueTypes.String);
n.AuthenticationTicket.Identity.AddClaim(idTokenClaim);
}
return Task.FromResult(0);
},
RedirectToIdentityProvider = n =>
{
// If authenticating, compute the redirect URI from the current request
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
n.ProtocolMessage.RedirectUri = new Uri(n.Request.Uri, "/authorization-code/callback").ToString();
// Make sure we're here because we're unauthenticated users and not
// just authenticated users without a valid role
if (n.OwinContext.Authentication.User.Identity.IsAuthenticated &&
n.OwinContext.Authentication.User.FindFirst(t => t.Type == ClaimTypes.Role && t.Value == "UserEmailValid") == null)
{
* // Pass control to the error message page
* // n.Response.Redirect(VirtualPathUtility.ToAbsolute("~/Errors/403.aspx"));
* n.OwinContext.Request.Path = new PathString(VirtualPathUtility.ToAbsolute("~/Errors/403.aspx"));
*** What here? I'm not in a middleware, this is a notification! ***
* n.HandleResponse();
}
}
// If signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
return Task.FromResult(0);
}
}
})
.UseStageMarker(PipelineStage.Authenticate);
Run Code Online (Sandbox Code Playgroud)
web.config授权示例:
<configuration>
<system.web>
<authorization>
<allow roles="UserEmailValid" />
<deny users="*" />
</authorization>
</system.web>
</configuration>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1110 次 |
| 最近记录: |