在自定义ActionFilterAttribute中访问自定义主体

时间:2010-08-06 18:15:49

标签: asp.net-mvc asp.net-mvc-2

我正在开发一个ASP.NET MVC应用程序。我实现了自定义成员资格提供者,主体和身份。在自定义提供程序中,我在ValidateUser()方法中替换HttpContext.Current.User,如下所示:

public sealed class CustomMembershipProvider : MembershipProvider {  
    ...  
    public override bool ValidateUser(string username, string password) {  
      ...  
      CustomIdentity identity = new CustomIdentity(...);  
      CustomPrincipal cu = new CustomPrincipal(identity);  
      HttpContext.Current.User = cu;  
      ...  
    }  
    ...  
}

在AccountController中(调用自定义成员资格提供程序),我可以按如下方式访问自定义标识:

public class AccountController : BaseController {  
  ...  
  public ActionResult LogOn(string userName,   
                            string password,   
                            bool rememberMe,   
                            string returnUrl) {  
    ...  
    CustomIdentity ci = (CustomIdentity)HttpContext.User.Identity;  
    ...  
  }  
  ...  
}

我的所有控制器都继承BaseController,它调用自定义属性,如下所示:

[CustomAttribute]  
public abstract class BaseController : Controller {  
  ...  
}  

我希望我的其他控制器在AccountController设置之后访问自定义属性中的自定义标识,如下所示:

public class CustomAttribute : ActionFilterAttribute {  
  public override void OnActionExecuting(ActionExecutingContext filterContext) {  
    base.OnActionExecuting(filterContext);  
    CustomIdentity ci = filterContext.HttpContext.User.Identity as CustomIdentity;  
    ...  
    }  
  }  
}  

我发现filterContext.HttpContext.User仍然设置为GenericPrincipal而不是我的CustomPrincipal。因此,我的自定义标识在我的属性过滤器中无法访问。我该怎么做才能在我的属性过滤器中访问我的CustomPrincipal?

提前致谢。

2 个答案:

答案 0 :(得分:2)

在研究了更多关于如何触发应用程序请求事件(特定顺序)以及何时可以设置上下文对象之后,我能够设置我的自定义主体和标识,以便它们可用于过滤器(在整个应用程序中) )。

我意识到必须先验证用户,然后才能将这些实体设置为通过应用程序的其余部分使用。我发现,这可以在global.asax的Application_AuthenticateRequest()方法中完成。

所以,我修改了我的逻辑如下:

  1. 从自定义提供程序的ValidateUser()方法中删除了创建自定义主体和标识。
  2. 相反,ValidateUser()在针对自定义存储库验证用户名和密码之后,使用用户名作为唯一键在HttpContext.Current.Cache中缓存我需要的任何信息。
  3. 最后,我在Application_AuthenticateRequest()中添加了以下逻辑,通过提取通用标识属性并使用我存储在缓存中的自定义属性来扩展它来设置我的自定义主体和标识。我使用存储在通用标识中的名称索引到缓存中,因为这是我用来创建缓存的密钥。
protected void Application_AuthenticateRequest(object sender, EventArgs e) {  

  if (Request.IsAuthenticated) {  

    // TODO: Add checks so we only do the following once per login.

    // Get the GenericPrincipal identity  
    IIdentity ui = HttpContext.Current.User.Identity;  

    /* Extract Name, isAuthenticated, AuthenticationType from
       the identity of the GenericPrincipal and add them including 
       any custom properties to the custom identity. I added a 
       few extra properties to my custom identity. */

    CustomIdentity identity = new CustomIdentity(...);

    /* Although my custom principal does not currently 
       have any additional properties, I created a new  
       principal as I plan to add them in the future. */

    CustomPrincipal principal = new CustomPrincipal(identity);

    // Set custom principal 
    HttpContext.Current.User = principal;

  }
}

这让我超越了我的障碍。如果还有其他更好的方法可以指导我,请指导我。

感谢。

答案 1 :(得分:0)

我不知道这是否“更好”,但到目前为止它对我有用。我创建了一个具有UserContext属性的静态CurrentUser类。在那里,我存储了从数据库中获取的用户实体,并将其用于用户信息数据和授权。我只使用HttpContext.Current.User来检查身份验证。

现在CurrentUser属性将我的用户对象存储在HttpContext的{​​{1}}集合中(我有一个包装器,所以我可以使它可单元测试)。