WebSeal反向代理背后的.Net Web应用程序

Shi*_*iji 3 asp.net reverse-proxy .net-4.0 .net-3.5 webseal

我们目前正在设计一个在WebSeal反向代理后面作为.Net Web应用程序运行的解决方案.

我在网上看到了一些评论,人们对此有各种各样的问题,例如重写viewstate.

问题是:有没有人实施这种技术组合并让它发挥作用?

Ema*_*eco 8

我在WEBSEAL后面创建了一个ASP.NET应用程序.经过大量的研究和开发和测试,它的工作原理.

我建议一些问题来帮助你:

IIS和ASP.NET不区分大小写

("... Login.aspx"和"... login.aspx"都导致同一页面); 默认情况下,webseal区分大小写.因此,您应该将WEBSEAL结点设置为不区分大小写或检查任何单个链接(页面,javascript,图像)

将不提供作为服务器相对URL编写的内部链接

WEBSEAL会更改引用您的应用程序的任何链接,但不会更改指向其他应用程序的链接.内部链接(作为服务器相对URL而不是应用程序相对URL)将不会更改(WEBSEAL不会识别它是相同的应用程序)并且不会被提供(WEBSEAL拒绝未修改的链接).
第一条规则是检查任何单个链接并使其成为应用程序相对URL.
如果您发现<.. href=/ anything>以下情况,请查看呈现的HTML :此ia服务器相对URL并且它很糟糕.
如果您使用"= ~/ anything"它,请查看代码背后是好的.如果你使用 "= / anything"OR ResolveUrl(..)则很糟糕.

但这还不够:AJAX将大量的javascript和代码放在ScriptResource.axdWebResource.axd中,并创建服务器相对URL来链接它.这些链接不受程序员的控制,也没有简单的方法来改变它们.
简单的解决方案(如果可能):解决问题设置WEBSEAL结是透明的.
硬解决方案:编写以下代码(感谢这个答案)

protected void Page_Load(object sender, EventArgs e)
    {
        //Initialises my dirty hack to remove the leading slash from all web reference files.
        Response.Filter = new WebResourceResponseFilter(Response.Filter);
    }

public class WebResourceResponseFilter : Stream
{
    private Stream baseStream;

    public WebResourceResponseFilter(Stream responseStream)
    {
        if (responseStream == null)
            throw new ArgumentNullException("ResponseStream");
        baseStream = responseStream;
    }

    public override bool CanRead
    { get { return baseStream.CanRead; } }

    public override bool CanSeek
    { get { return baseStream.CanSeek; } }

    public override bool CanWrite
    { get { return baseStream.CanWrite; } }

    public override void Flush()
    { baseStream.Flush(); }

    public override long Length
    { get { return baseStream.Length; } }

    public override long Position
    {
        get { return baseStream.Position; }
        set { baseStream.Position = value; }
    }

    public override int Read(byte[] buffer, int offset, int count)
    { return baseStream.Read(buffer, offset, count); }

    public override long Seek(long offset, System.IO.SeekOrigin origin)
    { return baseStream.Seek(offset, origin); }

    public override void SetLength(long value)
    { baseStream.SetLength(value); }

    public override void Write(byte[] buffer, int offset, int count)
    {
        //Get text from response stream.
        string originalText = System.Text.Encoding.UTF8.GetString(buffer, offset, count);

        //Alter the text.
        originalText = originalText.Replace(HttpContext.Current.Request.ApplicationPath + "/WebResource.axd",
            VirtualPathUtility.MakeRelative(HttpContext.Current.Request.Url.AbsolutePath, "~/WebResource.axd"));
        originalText = originalText.Replace(HttpContext.Current.Request.ApplicationPath + "/ScriptResource.axd",
            VirtualPathUtility.MakeRelative(HttpContext.Current.Request.Url.AbsolutePath, "~/ScriptResource.axd"));

        //Write the altered text to the response stream.
        buffer = System.Text.Encoding.UTF8.GetBytes(originalText);
        this.baseStream.Write(buffer, 0, buffer.Length);

    }
Run Code Online (Sandbox Code Playgroud)

这将拦截流到页面,并将所有出现的"/WebResource.axd"或"ScriptResource.axd"替换为"../../WebResource.axd"和"../../ScriptResource.axd"

开发代码以获得实际的WEBSEAL用户

WEBSEAL已配置为将用户名放在HTTP_IV_USER中.我创建了Webseal\Login.aspx表单以编程方式读取它.现在,为了使这个用户成为CurrentUser我放了一个隐藏的asp.Login

<span style="visibility:hidden"> 
<asp:Login ID="Login1" runat="server" DestinationPageUrl="~/Default.aspx">..
Run Code Online (Sandbox Code Playgroud)

并以编程方式单击该按钮

protected void Page_Load(object sender, EventArgs e)
{
    string username = Request.ServerVariables["HTTP_IV_USER"];
    (Login1.FindControl("Password") as TextBox).Text = MyCustomProvider.PswJump;
    if (!string.IsNullOrEmpty(username))
    {
        (Login1.FindControl("UserName") as TextBox).Text = username;
        Button btn = Login1.FindControl("LoginButton") as Button;
        ((IPostBackEventHandler)btn).RaisePostBackEvent(null);
     }
    else
    {
        lblError.Text = "Login error.";
    }
}
Run Code Online (Sandbox Code Playgroud)

LoginButton触发时,应用程序读取UserName(从WEBSEAL变量设置)和密码(硬编码).所以我实现了一个自定义成员资格提供程序,用于验证用户并设置当前Principal.

web.config中的更改

loginUrl是FormsAuthentication类将重定向到的登录页面的URL.它已设置为WEBSEAL门户:未经过身份验证的用户和注销按钮将重定向到门户网站.

<authentication mode="Forms">
  <forms loginUrl="https://my.webseal.portal/" defaultUrl="default.aspx"...."/>
</authentication>
Run Code Online (Sandbox Code Playgroud)

由于Webseal/login.aspx不是默认登录页面,因此授权标记授予对未经过身份验证的用户的访问权限:

<location path="Webseal/login.aspx">
    <system.web>
        <authorization>
            <allow users="*"/>
        </authorization>
    </system.web>
</location>
Run Code Online (Sandbox Code Playgroud)

应用程序设置为使用自定义成员资格提供

 <membership defaultProvider="MyCustomMembershipProvider">
  <providers>
    <add name="MyCustomMembershipProvider" type="MyNamespace.MyCustomMembershipProvider" connectionStringName="LocalSqlServer"/>
  </providers>
</membership>
<roleManager enabled="true" defaultProvider="MyCustomRoleProvider">
  <providers>
    <add name="MyCustomRoleProvider" type="MyNamespace.MyCustomRoleProvider" connectionStringName="LocalSqlServer"/>
  </providers>
</roleManager>
Run Code Online (Sandbox Code Playgroud)

Debug设置为off:

<compilation debug="false" targetFramework="4.0">
Run Code Online (Sandbox Code Playgroud)

这是所有人!