EPiServer 和 Windows Identity Foundation (WIF)

发布于 2024-12-13 05:08:50 字数 3155 浏览 0 评论 0 原文

我正在研究使用 WIF 来识别在 EPiServer 上运行的客户网站部分上的用户的可能性。我已经设法让 WIF 启动,除其他外,使用以下帖子:

http://world.episerver.com/Blogs/Ben-Morris/Dates/2010/6/Converting-EPiServer-6-to-use-claims-based-authentication-with-WIF/

如果您

<authorization>
    <deny users="?"/>
</authorization>

在 web.config 中设置,使所有请求都需要经过身份验证的用户,那么这会很好地工作。但是,我们希望使用 EPiServer 来区分匿名用户和经过身份验证的用户可以使用哪些内容。问题是,我就是无法让它发挥作用。

当我启用 WIF 并且不设置 deny users="*" 时,EPiServer 会启动并向响应流输出一些文本,然后再启用 WIF 执行重定向:

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Tue, 01 Nov 2011 07:51:04 GMT
Connection: close

Access denied.

</pre></table></table></table></table></table></font></font></font></font></font></i></i></i></i></i></b></b></b></b></b></u></u></u></u></u><p>&nbsp;</p><hr>

这会导致以下错误当 WIF 尝试重定向到 STS 时:

“/”应用程序中的服务器错误。

发送 HTTP 标头后无法重定向。

描述:执行期间发生未处理的异常 当前的网络请求。请查看堆栈跟踪以了解更多信息 有关错误及其在代码中的来源的信息。

异常详细信息:System.Web.HttpException:之后无法重定向 HTTP 标头已发送。

来源错误:

执行过程中产生了未处理的异常 当前的网络请求。有关原产地和地点的信息 可以使用下面的异常堆栈跟踪来识别异常。

堆栈跟踪:

[HttpException (0x80004005): 在 HTTP 标头包含后无法重定向 已发送。] System.Web.HttpResponse.Redirect(String url, Boolean 结束响应)+8712587
Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.RedirectToIdentityProvider(字符串 uniqueId、字符串 returnUrl、布尔值持续)+249
Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.OnEndRequest(对象 发送者,EventArgs 参数)+438
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +68 System.Web.HttpApplication.ExecuteStep(IExecutionStep 步骤,Boolean&completedSynchronously) +75

我已经搜索了高和低以便能够覆盖此行为。在 EPiServer.dll 中,我发现以下位置输出的文本与输出内容类似:

AccessDeniedDelegateHandler.cs,方法 BrowserLogonAccessDenied(object sender)

internal static void BrowserLogonAccessDenied(object sender)
{
  HttpContext.Current.Response.Clear();
  HttpContext.Current.Response.Status = "401 Unauthorized";
  HttpContext.Current.Response.Write("Access denied.");
  HttpContext.Current.Response.Flush();
  HttpContext.Current.Response.End();
}

此代码是从据我所知,以下两个地方:

  • EPiServer.Global,方法protected virtual void HandleAccessDenied()
  • EPiServer.PageBase,方法public virtual void AccessDenied()

我尝试覆盖Global.asax中的HandleAccessDenied,并覆盖我的页面模板中的 AccessDenied 。但是,仍然输出“访问被拒绝”文本。看起来好像我的页面模板中的 AccessDenied 覆盖正在触发,但是 HandleAccessDenied 的覆盖似乎没有触发。

关于这里可能出什么问题的任何提示吗?

I am researching the possibilities of using WIF to identify users on parts of a customer's site running on EPiServer. I've managed to get WIF to kick in using, amongst others, the following post:

http://world.episerver.com/Blogs/Ben-Morris/Dates/2010/6/Converting-EPiServer-6-to-use-claims-based-authentication-with-WIF/

This works nicely if you set

<authorization>
    <deny users="?"/>
</authorization>

in web.config, making all requests require an authenticated user. However, we would like to use EPiServer to separate what content should be available to anonymous users and authenticated users. The problem is, I just can't get it to work.

When I enable WIF, and don't set deny users="*", EPiServer kicks in and outputs some text to the response stream before WIF is enable to perform the redirect:

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Tue, 01 Nov 2011 07:51:04 GMT
Connection: close

Access denied.

</pre></table></table></table></table></table></font></font></font></font></font></i></i></i></i></i></b></b></b></b></b></u></u></u></u></u><p> </p><hr>

This results in the following error when WIF tries to redirect to the STS:

Server Error in '/' Application.

Cannot redirect after HTTP headers have been sent.

Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: Cannot redirect after
HTTP headers have been sent.

Source Error:

An unhandled exception was generated during the execution of the
current web request. Information regarding the origin and location of
the exception can be identified using the exception stack trace below.

Stack Trace:

[HttpException (0x80004005): Cannot redirect after HTTP headers have
been sent.] System.Web.HttpResponse.Redirect(String url, Boolean
endResponse) +8712587
Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.RedirectToIdentityProvider(String
uniqueId, String returnUrl, Boolean persist) +249
Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.OnEndRequest(Object
sender, EventArgs args) +438
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
+68 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

I have searched both high and low to be able to override this behavior. In EPiServer.dll, I found the following place which outputs text similar to what is output:

AccessDeniedDelegateHandler.cs, method BrowserLogonAccessDenied(object sender):

internal static void BrowserLogonAccessDenied(object sender)
{
  HttpContext.Current.Response.Clear();
  HttpContext.Current.Response.Status = "401 Unauthorized";
  HttpContext.Current.Response.Write("Access denied.");
  HttpContext.Current.Response.Flush();
  HttpContext.Current.Response.End();
}

This code is called from the following two places, as far as I can see:

  • EPiServer.Global, method protected virtual void HandleAccessDenied()
  • EPiServer.PageBase, method public virtual void AccessDenied()

I have tried to override HandleAccessDenied in Global.asax, and override AccessDenied in my page template. However, the "Access denied" text is still output. It looks as if the override of AcccessDenied in my page template is firing, however, the override of HandleAccessDenied does not seem to fire.

Any hints on what could be wrong here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吝吻 2024-12-20 05:08:50

发现问题了。我尝试覆盖 PageBaseAccessDenied 方法,但是,我犯了与默认实现相同的“错误”,即刷新响应流:

    public override void AccessDenied()
    {
        Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        Response.Flush(); // <- This was the problem
        Response.End();
        // The rest is handled by WIF when we send a HTTP 401, think nothing more of it..
    }

解决方案是简单地避免刷新响应流。然后 WIF 处理剩下的事情:

    public override void AccessDenied()
    {
        Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        // Removed the flushing of the response
        Response.End();
        // The rest is handled by WIF when we send a HTTP 401, think nothing more of it..
    }

这允许我们使用 EPI 的授权来控制哪些用户可以访问每个页面。

Found the problem. I tried overriding the AccessDenied method of PageBase, however, I did the same "mistake" as the default implementation, namely to flush the response stream:

    public override void AccessDenied()
    {
        Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        Response.Flush(); // <- This was the problem
        Response.End();
        // The rest is handled by WIF when we send a HTTP 401, think nothing more of it..
    }

The solution was to simply avoid flushing the response stream. Then WIF handles the rest:

    public override void AccessDenied()
    {
        Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        // Removed the flushing of the response
        Response.End();
        // The rest is handled by WIF when we send a HTTP 401, think nothing more of it..
    }

This allows us to use the authorization of EPI to control which users had access to each page.

情深如许 2024-12-20 05:08:50

您可以添加一个特殊的登录表单(因为您仍然依赖表单身份验证)来实际触发登录,而不是覆盖 AccessDenied 行为。

public class FederatedLoginHandler : IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.User.Identity.IsAuthenticated)
        {
            FormsAuthentication.RedirectFromLoginPage(context.User.Identity.Name, false);
        }
        else
        {
            context.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
        }
    }
}

在 web.config 中设置处理程序

<system.webServer>
  <handlers>
    <!--"Fake" login handler, simply triggers WIF auth-->
    <add name="LoginForm" path="federatedlogin.ashx" verb="GET,HEAD" type="SomeAssembly.FederatedLoginHandler" />
    ...

最后设置身份验证以使用新处理程序

<authentication mode="Forms">
  <forms name=".LoginPage" loginUrl="federatedlogin.ashx" timeout="120" />
</authentication>

此策略不需要修改 EPiServer、WIF 或标准 ASP.Net 行为。当然,您需要基本的 WIF 配置才能使其正常工作 http://msdn .microsoft.com/en-us/library/gg638734.aspx

Instead of overriding the AccessDenied behaviour, you can add a special login form (since you are still relying on forms authentication) to actually trigger the login.

public class FederatedLoginHandler : IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.User.Identity.IsAuthenticated)
        {
            FormsAuthentication.RedirectFromLoginPage(context.User.Identity.Name, false);
        }
        else
        {
            context.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
        }
    }
}

Setup the handler in web.config with

<system.webServer>
  <handlers>
    <!--"Fake" login handler, simply triggers WIF auth-->
    <add name="LoginForm" path="federatedlogin.ashx" verb="GET,HEAD" type="SomeAssembly.FederatedLoginHandler" />
    ...

And finally setup authentication to use the new handler

<authentication mode="Forms">
  <forms name=".LoginPage" loginUrl="federatedlogin.ashx" timeout="120" />
</authentication>

This strategy does not require modifying EPiServer, WIF or standard ASP.Net behaviour. Of course, you need the basic WIF configuration to get this to work http://msdn.microsoft.com/en-us/library/gg638734.aspx.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文