如何全局创建CustomPrincipal(使用和不使用AuthorizeAttribute)

时间:2012-07-13 18:33:42

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

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

这适用于使用我的AuthorizeAttribute修饰的控制器/操作,但是,对于不需要身份验证的控制器(但如果它在那里仍然使用它),我想得到我的CustomPrincipal(并且最好通过HttpContext.User)

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

同样,如果在每个具有auth cookie的请求中都这样做,那么如果在AuthorizeAttribute修饰的控制器的情况下,我将如何避免两次工作(这将成为一个强制认证)。

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

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

  • 使用会话(并处理逻辑来创建我需要的东西,忘记校长)
  • Application_AuthenticateRequest - 在网上看到这是旧学校的评论
  • 在基本控制器上设置自定义过滤器
  • 在基本控制器上创建一个AuthorizationAttribute,让每个人都能通过并设置我想要的HttpContext.User
  • IHttpModule - 这似乎是一种下降的方式(除非其他人不同意,否则沿着这条路走下去)。

思想?

2 个答案:

答案 0 :(得分:18)

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

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

    ...
}

答案 1 :(得分:0)

覆盖原则:

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)

而不是

protected void Application_AuthenticateRequest(object sender, EventArgs e)

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