使用FormsAuthentication以编程方式测试对给定路径的访问

时间:2014-10-06 13:47:15

标签: asp.net forms-authentication

是否可以通过编程方式测试当前用户是否能够访问给定路径?这将是我需要限制访问的某个资源的路径,它将是一个通过处理程序而不是直接通过其路径访问的资源。

例如,给定以下配置设置:

<authentication mode="Forms">
  <forms loginUrl="~/login/" defaultUrl="~/private/" protection="All" cookieless="UseCookies" slidingExpiration="true" path="/" />
</authentication>

...

<location path="private">
  <system.web>
    <authorization>
      <deny users="?" />
      <allow users="*" />
    </authorization>
  </system.web>
</location>
<location path="private/general">
  <system.web>
    <authorization>
      <allow roles="general" />
      <deny users="*" />
    </authorization>
  </system.web>
</location>

我们可以这样做吗?:

HttpContext.Current.User.Identity.IsAllowedToAccess("~/private/general/my-resource")

哪些会为“普通”角色中的用户返回true,为其他任何人返回false

请注意,配置设置只是一个示例 - 可能会有更多的位置定义和角色等,因此使用大量myPath.StartsWith("/private/")语句进行测试并不是一个很好的解决方案。

1 个答案:

答案 0 :(得分:0)

我从来没有完全理解这一点,所以我不得不稍微改变一下方法。

这假设我们尝试获取的资源通常不会由IIS提供 - 在我的情况下,这是Web表单用户控件(.ascx),我想要的通过Ajax获取,呈现为一个字符串,然后可以通过JavaScript在HTML中的某个地方注入。

我摆脱了处理程序,而是将其设置为使得对这些资源的任何请求都直接发送到资源,但稍微修改了.ascx.asmx扩展名。例如,/private/general/my-resource.ascx.asmx

然后我添加了一个HTTP模块(集成管道模式):

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <add name="MyResourceHttpModule" type="MyApp.Controls.MyResourceHttpModule" />
  </modules>
</system.webServer>

(或经典的管道模式):

<system.web>
  <httpModules>
    <add name="MyResourceHttpModule" type="MyApp.Controls.MyResourceHttpModule" />
  </httpModules>
</system.web>

相关代码:

using System;
using System.Web;

namespace MyApp.Controls
{
    public class MyResourceHttpModule : IHttpModule
    {
        #region IHttpModule Members

        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
        }

        #endregion

        void OnAuthorizeRequest(object sender, EventArgs e)
        {
            var application = (HttpApplication)sender;

            if (application.Context.Request.Url.AbsolutePath.EndsWith(".ascx.asmx"))
            {
                application.Context.RewritePath("~/Services/MyResource.asmx/GetResource");
            }
        }
    }
}

此模块将请求的URL重写为Web服务(MyResource.asmx),然后剥离我们最初添加的额外扩展,最后提供我们尝试访问的文件(在本例中为web表单用户控件):

using System.Collections.Generic;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;

namespace MyApp.Services
{
    [ScriptService]
    public class MyResource : System.Web.Services.WebService
    {
        [WebMethod(EnableSession = true)]
        public object GetResource()
        {
            var controlPath = HttpContext.Current.Request.RawUrl;

            if (Paths.ApplicationPath != "" && controlPath.StartsWith(Paths.ApplicationPath)) controlPath = '~' + controlPath.Substring(Paths.ApplicationPath.Length);
            if (controlPath.EndsWith(".asmx")) controlPath = controlPath.Substring(0, controlPath.Length - 5);

            using (var myUserControl = (MyApp.Controls.MyUserControl)(new Page()).LoadControl(controlPath))
            {
                myUserControl.DataBind();

                return myUserControl.RenderToString();
            }
        }
    }
}

(这使用此RenderToString扩展方法):

public static string RenderToString(this System.Web.UI.Control control)
{
    var stringBuilder = new StringBuilder();

    using (var stringWriter = new StringWriter(stringBuilder))
    {
        using (var htmlTextWriter = new System.Web.UI.HtmlTextWriter(stringWriter))
        {
            control.RenderControl(htmlTextWriter);

            return stringBuilder.ToString();
        }
    }
}

这一切都有效,因为表单身份验证在允许请求之前通过web.config中设置的授权规则运行,因此我们知道,当它到达我们的HTTP模块时,可以提供所请求的文件,因为当前用户必须有权访问该路径。