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:
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).
上一篇: 使用自定义类重载EF验证