【问题标题】:How to create a CustomPrincipal globally (with and without AuthorizeAttribute)如何全局创建 CustomPrincipal(有和没有 AuthorizeAttribute)
【发布时间】:2012-07-13 18:33:42
【问题描述】:

我的 ASP.NET MVC4 Web 应用程序有一个自定义主体/身份。我还创建了一个 AuthorizeAttribute 来实例化我的自定义主体,将其分配给我需要身份验证的控制器中的 httpContext.User。

这对于使用我的 AuthorizeAttribute 修饰的控制器/操作非常有用,但是,对于不需要身份验证的控制器(但如果它存在的话仍然使用它),我想获得我的 CustomPrincipal (最好通过 HttpContext.User).

在这些未修饰的控制器/动作中,设置了 HttpContext.User,但使用的是 GenericPrincipal 而不是我的 CustomPrincipal。 将 HttpContext.User 的默认设置“覆盖”到 GenericPrincipal 的最佳位置在哪里?

同样,如果在每个具有身份验证 cookie 的请求中都执行此操作,在 AuthorizeAttribute 装饰控制器的情况下,我将如何避免做两次工作(然后它会变成一个强制认证)。

为了清楚起见,我的网站允许匿名用户访问,但在这些页面上,如果某个页面通过了身份验证(并且实现了 CustomPrincipal),则提供了额外的功能。

我认为有些选项是(不确定每个选项背后的逻辑):

  • 使用会话(并处理逻辑来创建我需要的内容,忘记 Principals)
  • Application_AuthenticateRequest - 在网络上看到 cmet 认为这是老派
  • 在基本控制器上设置自定义过滤器
  • 在基本控制器上创建一个 AuthorizationAttribute,让每个人都可以通过并根据需要设置 HttpContext.User
  • IHttpModule - 这似乎是一种下降方式(除非其他人不同意,否则沿着这条路前进)。

想法?

【问题讨论】:

  • AuthenticateRequest 有什么问题?您只是觉得有问题还是发现了技术问题?我问这个,因为我相信自定义模块上的 AuthenticateRequest 是正确的方法。
  • 使用 application_authenticaterequest 或 ihttpmodule 挂钩到 authenticaterequest 本质上是等效的。只是模块可以在运行时换出,重用等比 global.asax 中的代码块更容易

标签: asp.net asp.net-mvc forms-authentication iprincipal


【解决方案1】:

您可以使用全局操作过滤器。假设您有一个自定义主体:

public class MyPrincipal : GenericPrincipal
{
    public MyPrincipal(IIdentity identity, string[] roles): base(identity, roles)
    {
    }

    ... some custom properties and stuff
}

然后您可以编写一个全局授权操作过滤器(但它不是从基本AuthorizeAttribute 派生以避免全局身份验证,它只是实现IAuthorizationFilter 接口以确保它在任何其他过滤器之前运行):

public class GlobalIdentityInjector : ActionFilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var identity = filterContext.HttpContext.User.Identity;

        // do some stuff here and assign a custom principal:
        var principal = new MyPrincipal(identity, null);
        // here you can assign some custom property that every user 
        // (even the non-authenticated have)

        // set the custom principal
        filterContext.HttpContext.User = principal;
    }
}

全局过滤器将在~/App_Start/FilterConfig.cs 中注册,以保证它适用于所有操作:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new GlobalIdentityInjector());
    }
}

现在您可以拥有一个自定义授权属性,该属性仅适用于某些需要身份验证的控制器操作:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            return false;
        }

        // we know that at this stage we have our custom
        // principal injected by the global action filter
        var myPrincipal = (MyPrincipal)httpContext.User;

        // do some additional work here to enrich this custom principal
        // by setting some other properties that apply only to
        // authenticated users

        return true;

    }
}

然后你可以有两种类型的动作:

public ActionResult Foo()
{
    var user = (MyPrincipal)User;

    // work with the custom properties that apply only
    // to anonymous users

    ...
}

[MyAuthorize]
public ActionResult Bar()
{
    var user = (MyPrincipal)User;

    // here you can work with all the properties
    // because we know that the custom authorization
    // attribute set them and the global filter set the other properties

    ...
}

【讨论】:

  • 优秀,详细的答案达林。如果只是为了从您那里收集更多 MVC 架构信息,您能否谈谈为什么您会选择全局操作过滤器而不是其他选择?
  • 您的第一个建议是毫无疑问的,因为它涉及使用会话。我个人从不使用会话。 Application_AuthenticateRequest 不是 MVCish。第三个和第四个我不喜欢,因为基本控制器。最后一个 - IHttpModule 我不喜欢,因为不是 MVCish。所以我选择了一个全局动作过滤器——它不需要实现一个基本控制器(开发人员可能忘记从中派生),它普遍应用于所有请求,这是在 ASP.NET MVC 应用程序中实现此类功能的非常常见的方式.
  • 差不多一年后,这极大地救了我。非常感谢达林。
【解决方案2】:

覆盖主体:

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)

代替

protected void Application_AuthenticateRequest(object sender, EventArgs e)

在 Global.asax.cs 中为我在 ASP Web 应用程序中工作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多