如何在全球范围内建立一个CustomPrincipal(有和没有AuthorizeAttribute

2019-06-26 07:00发布

我有我的ASP.NET MVC4 web应用程序自定义用户/身份。 我还创建了一个AuthorizeAttribute实例我自定义的校长,在我需要验证控制器将其分配给HttpContext.User中。

这对于已经装饰了我的AuthorizeAttribute控制器/行动的伟大工程, 但是,对于那些不要求身份验证(但仍使用它,如果它是存在的)控制器,我想,让我的CustomPrincipal(最好是通过HttpContext.User中)。

在这些非装饰控制器/动作,HttpContext.User中设置,但有一个的GenericPrincipal,而不是我的CustomPrincipal。 将在什么地方最好的地方,“覆盖”一个HttpContext.User中到的GenericPrincipal的默认设置?

同样,如果这是一个具有权威性的cookie, 我怎么会那么避免在AuthorizeAttribute装饰控制器 (然后将刚刚成为一个授权认证) 的情况下所做的工作两次每个请求完成。

只是要清楚,我的网站允许匿名用户访问,但在这些网页中,如果一个被认证(和CustomPrincipal实现),提供额外的功能。

我觉得有些选项是(不是一定每个人背后说我逻辑的):

  • 使用一个会话(和处理逻辑来创造什么我需要在这里,忘记了校长)
  • Application_AuthenticateRequest - 各地的网络看到评论说,这是老学校
  • 自定义过滤器基部控制器上设置
  • 主控制器,通过让每个人,树立HttpContext.User中,因为我想它在创建AuthorizationAttribute
  • IHttpModule的 - 这似乎是一个下降的方式(和航向沿着这条道路,除非其他人不同意)。

思考?

Answer 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;

    }
}

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

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

    ...
}


Answer 2:

Overridding主要在:

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)

代替

protected void Application_AuthenticateRequest(object sender, EventArgs e)

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



文章来源: How to create a CustomPrincipal globally (with and without AuthorizeAttribute)