views:

341

answers:

5

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:

Lets 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?

Thanks

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.

+1  A: 

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.

Agent_9191
I thought about using referrer but thats not secure. If I return ActionResult, would that be just the same as executing both pieces of code in the same Action?
Teto
You could execute the code behind the scenes for the regular Index action first, and then have a line like `return Index2();` after all the specific Index() code.
Agent_9191
+2  A: 

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.

tvanfosson
Teto
TempData is available in MVC 1.0.
tvanfosson
A: 

You could define routing:

routes.MapRoute(
            "Index2Redirect",
            "HomeController/Index2",
            new { controller = "HomeController", action = "Index", id = "" }
        );

EDIT:

No, it is not good.

LukLed
If Index redirects to Index2, then this would result in an infinite loop of redirects wouldn't it?
tvanfosson
A: 

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.

queen3
My problem is that I need to ensure to "kill" the session completely. i.e., Expire the forms auth cookie as well as the ASP.Net_SessionId one. Session.Abandon() and FormsAuthentication.SignOut() methods. A new session will only start once a new requests comes from the client (along with a new sessionId) so all these solutions using session are not useful for us (since a new session id will be used from the next request onwards). Would some sample code help perhaps?
Teto
A: 

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

Teto