问题
We have an MVC app which has a custom forms authentication view/controller. The controller will verify things and then do a FormsAuthentication.RedirectFromLoginPage call.
At this point in the Global.asax we'll receive a Application_OnAuthenticateRequest call from where we'll get their Context.User information and make another call to gather information relevant to this account which we then store in their Context.User & System.Threading.Thread.CurrentPrincipal. We also do a little caching of this information since in our system retrieving what we need is expensive which leads to cache invalidation & re-retrieval of this information.
It seems a bit odd at this point that we've got these separated into separate calls. I'm almost wondering if the Login controller shouldn't be gathering the details as part of its authentication check and storing them. Then the Application_OnAuthenticateRequest can only worry about if the cache needs to be invalidated and the users details re-retrieved.
Or maybe there is some other way of handling this I don't even know about..?
回答1:
You can do what you want in MVC by leveraging RedirectToRouteResult
and a custom cache updating ActionFilter
. This is called the PRG (Post-Redirect-Get) pattern. You are actually already doing this, but it gets a little confused, because what you are doing is a cross between the classic ASP.NET way of doing things and the MVC way of doing things. There's nothing wrong with your initial approach (provided it is working correctly), but to do the same sort of thing and have more control and understanding of how it works in the scheme of things you could do something like:
public class AuthenticationController :Controller
{
[HttpPost]
public RedirectToRouteResult Login(string username, string password)
{
//authenticate user
//store authentication info in TempData like
bool authenticated = true|false; // do your testing
if(authenticated)
{
TempData["MustUpdateCache"] = true | false;
return RedirectToAction("LoginSuccess", new{userId = membershipUser.UserId});
}
else
{
TempData["MustUpdateCache"] = true | false;
return RedirectToAction("Login");
}
}
[HttpGet, UpdateCache]
public ActionResult LoginSuccess(Guid userId, string url)
{
HttpContext.User = LoadUser(userId);
return View();
}
[HttpGet, UpdateCache]
public ViewResult Login()
{
return View();
}
}
public class UpdateCacheAttribute:ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var tempData = filterContext.Controller.TempData;
if (tempData.ContainsKey("MustUpdateCache") && (bool)tempData["MustUpdateCache"])
{
UpdateCache(filterContext);
}
}
void UpdateCache(ControllerContext controllerContext)
{
//update your cache here
}
}
来源:https://stackoverflow.com/questions/5437745/two-step-authentication-in-mvc