Accessing custom principal within a custom ActionFilterAttribute

I am working on an ASP.NET MVC application. I have implemented custom membership provider, principal and identity. In the custom provider I replace the HttpContext.Current.User in the ValidateUser() method as follows:

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;  
      ...  
    }  
    ...  
}

In the AccountController (calls the custom membership provider) I am able to access the custom identity as follows:

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

All my controllers inherit the BaseController which calls a custom attribute as follows:

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

I want my other controllers to access the custom identity within the custom attribute after it has been set by the AccountController as follows:

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

What I have found is that filterContext.HttpContext.User is still set to GenericPrincipal and not my CustomPrincipal. So my custom identity is not accessible within my attribute filter. What do I have to do so that my CustomPrincipal is accessible within my attribute filter?

Thanks in advance.


After researching more about how application request events are fired (the specific order) and when context objects can be set I was able to set my custom principal and identity so that they are available to the filter (throughout the application for that matter).

I realized that the user must be authenticated before these entities could be set for use through the rest of the application. This, I found, could be done in the Application_AuthenticateRequest() method of global.asax.

So, I modified my logic as follows:

  • Removed creating custom principal and identity from the custom provider's ValidateUser() method.
  • Instead, ValidateUser() after verifying username and password against the custom repository, caches whatever information I needed within HttpContext.Current.Cache using the user name as the unique key.
  • Finally, I added the following logic in Application_AuthenticateRequest() to set set my custom principal and identity by extracting the generic identity properties and extending it with custom properties that I stored in the cache. I indexed into the cache using the name stored within generic identity as that is the key I used to create the cache.
    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;
    
      }
    }
    

    This got me past my hurdle. Please guide me if there are other better ways to accomplish the same.

    Thanks.


    I don't know if this is "better" way, but it worked for me so far. I create a static UserContext class that has CurrentUser property. There I store the user entity I get from database and use it for user info data and authorization. I only use the HttpContext.Current.User to check authentication.

    Now the CurrentUser property stores my user object in HttpContext 's Items colletion (I have a wrapper around that so I can make it unit testable).

    链接地址: http://www.djcxy.com/p/56576.html

    上一篇: 使用自定义类重载EF验证

    下一篇: 在自定义ActionFilterAttribute中访问自定义主体