OWIN OpenId Connect身份验证和基于角色的授权

时间:2020-03-26 22:46:59

标签: asp.net webforms owin openid-connect katana

我有一个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>

0 个答案:

没有答案