我有一个WebForms应用程序(不是MVC,不是WebApi),我正在移植到OpenID Connect外部身份验证(.net 4.7.2,最新的OWIN NuGet软件包)。此Web应用程序使用基于角色的授权,以防止未经授权的用户访问应用程序的某些部分。角色通过OIDC声明提供,并在Web应用程序中指定为web.config
授权条目。
主要流程起作用:当用户未通过身份验证并且用户在ClaimsIdentity中具有适当的角色时,应用程序将用户正确重定向到OIDC提供程序。
当用户登录但没有访问角色受限区域所需的角色时,就会发生问题。在这种情况下,UrlAuthorizationModule
返回401未经授权的错误(难道不是403禁止吗?!),这会触发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);
web.config授权示例:
<configuration>
<system.web>
<authorization>
<allow roles="UserEmailValid" />
<deny users="*" />
</authorization>
</system.web>
</configuration>