Is it possible to block an action to be executed directly from the browser, but still be able to redirect to it from inside the site? I know it sounds stupid but this is what I want:
Let's say there are two routes, Index
and Index2
of HomeController
.
www.website.com/home
will cause Index to be executed, I then want to execute some code and then redirect (or server transfer) to www.website.com/home/index2
.
I don't want the URL www.website.com/home/index2
to be accessed directly by the user, without going to home/index
first.
Is there something I can do to deactivate/activate the route at runtime?
EDIT: Sorry, this question is 开发者_运维百科titled "Session Fixation" because I need Index
to run prior to Index2
to ensure we are killing all Sessions in Index
and renewing them before Index2
executes.
I cannot kill the session and execute the code in Index2
in the same request since Index2
needs session to do its job.
Not if you do a redirect. If you do a redirect it will appear to the controller the same way as if the request simply originated at the browser (which it does). You could gin something up with TempData -- i.e. set a flag there and only execute the action if the flag is in TempData -- but if it isn't the next request from the browser it will fail. That is, you may get another request, say via AJAX, that comes between the original and the redirect. The TempData would be wiped out by that request.
If, on the other hand, you simply want to execute the code, then don't expose Index2 as a public method and call it directly. If it's in the same controller, this should just work. You'll end up with the same URL, but if it's just getting the correct view that you want this should be ok.
If the user is redirected to www.website.com/home/index2, then they have to make the browser request even if it's automatically happening on their behalf. The only way to prevent that is to perform a check on the Index2 action that checks the HTTP Referer.
Another option would be to have Index return the ActionResult of Index2, that way the URL remains at /home/index, but the results of Index2 are returned and as far as the user is concerned they were never redirected.
You can put an ActionFilter and do your session cleanup / etc from there. This way your code will always be executed before Index2 - and before any action for which you put this attribute.
public class AbandonSessionAttribute: ActionFilterAttribute
{
public void OnActionExecuting(ActionFilterContext context)
{
if (Session.User.IsAuthenticated || Session.Count > 0) // <<-- this is the important line
{
Session.Clear();
FormsAuthentication.SignOut(); // and so on
context.Result = new RedirectResult("/Index2");
}
}
}
// now, if this is called with non-empty session, it will be cleared and user will be redirected again here
[AbandonSession]
public ActionResult Index2()
{
}
Notice the "this is the important line". There you need to detect if user is allowed to enter Index2. I do it by checking that Session is not empty. However, after the redirect MVC may add it's own Session variables, so Session won't ever be empty and the filter will redirect again and again... You'll need to find out what is OK to be presented in Session. From your question it's not clear (for me) if ANY navigation to Index2 should clear the session - i.e. during site browsing. If so, code above is OK, if not - it's up to you to decide how to detect this (for example, put something into session on some pages and remove from there on others).
Again, I don't see why Session won't work for you (and by the way TempData also works via Session). If the action filter you detect that request is not "clean" - there're login, session vars, etc - so you cleanup this and redirect once again to the same action - this causes new Session creation and so on. This time the filter doesn't find anything - since the Session has just been cleaned up - and so action is allowed to execute.
OK, this is what we ended up doing. Anyone see any caveats with this approach?
Index()
{
expire all session and forms-Authententication cookies
}
Index2()
{
if(Session.IsNewSession)
{
redirect to Index action
}
else
{
Show view
}
}
You could define routing:
routes.MapRoute(
"Index2Redirect",
"HomeController/Index2",
new { controller = "HomeController", action = "Index", id = "" }
);
EDIT:
No, it is not good.
精彩评论