Wednesday, August 26, 2009

Developer AutoLogin & Redirect

A large project I'm working on these days includes a Login page which each user must pass through before being able to access the rest of the site. There is code similar to this that prevents unauthorized entry onto every page:












For some time I would just comment out this code until the rest of the module was complete. The problem with that is that as the application became more & more sophisticated, there was assorted initialization code elsewhere that has to be executed each & every time.

For the Run-Debug cycle it became exceptionally time consuming (and annoying) to manually go through the entire login process every time. Here's an example of the steps involved:







































Oh sure, it's just a few keystrokes and mouse clicks each time but repeated dozens (or hundreds!) of times per day, one soon hopes for a way to automate the process. And I found it!



In Visual Studio's Solution Explorer, right-click on whatever page you're working on and choose "Set As Start Page" from the popup menu. Note: You've probably already done this!

Now in the Page_Init event handler of your Master Page (FYI all my projects use Master Pages) add this code:

protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
// If we're on a development machine then record the Start Page that Visual Studio is set to
string currPage = Page.ResolveUrl(Request.ServerVariables["URL"].ToString());
if (System.Diagnostics.Debugger.IsAttached && SessionData.GetCurrentUser() == "")
if (SessionData.GetSessionObject("CurrentDebugPage") == null)
SessionData.SaveSessionObject("CurrentDebugPage", currPage);
}
}

Then in the Page_Load event handler of your login page add this code:

// Note: This must be set above: using System.Web.Security;
protected void Page_Load(object sender, EventArgs e)
{
// This tests whether we're running on a development machine. If so, we'll automatically login.
if (System.Diagnostics.Debugger.IsAttached && SessionData.GetCurrentUser() == "")
{
string currUser = "your_username";

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(currUser, false, 5);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);

// If a specific page has been set as the Start Page then redirect to it; otherwise go to the Default page
string currDebugPage = SessionData.GetSessionObject("CurrentDebugPage").ToString();
HttpContext.Current.Response.Redirect((currDebugPage == null) ? "~/default.aspx" : currDebugPage, true);
}
}

Note: The various SessionData methods are just simple ones I've constructed to ease the process of storing & retrieving variables in the Session State. I will gladly provide them upon request.



The result is that now, every time I run my project in Visual Studio, it jumps right to the desired web page, logging me in automatically. And yet when run in non-Debug mode it works normally. So I don't have to alter any code whenever I release a new production version.

In case you're wondering how this works, the process is quite straightforward:
  1. The Master page's Page_Init event handler is run before every Content page's Page_Load event handler. It records the start page that the developer wanted to go to, placing this string into a Session variable.
  2. When that desired page's Page_Load event handler is initially entered, the security checks therein reject entry because the user is not logged in. They then redirect to the Login page.
  3. In the Login page the special test in Page_Load passes because the code is being run from Visual Studio and because the user is not yet logged in.
  4. A FormsAuthenticationTicket is instantiated and then placed in a Cookie. This allows one to artificially login through the ASP.Net Login mechanism.
  5. The desired start page, originally stored by the Master Page, is retrieved from the Session State and control is redirected to that page.
  6. This second time the security checks in the desired page's Page_Load event handler pass because the user is now officially logged in.
It actually works really well and will save you a lot of time! If you have any questions, please just leave a comment.

4 comments:

  1. Wow thats nice... I will definitely try this on the project that I am working on...

    ReplyDelete
  2. Does this work when you have roles and location's setup? I dont put any code in my pages to handle the login mechanism as asp.net has always handled it for me?

    ReplyDelete
  3. Harry, I'm guessing that you have your project locked down with Web.sitemap? Way back when I tried doing that but it never gave me enough flexibility to let Web.sitemap properly map into my menu structure. So instead I build the menu structure the way I like with a very simple method I constructed.

    In any case, I *think* my approach here would work properly because the code would still login the user and thus pass the automated validation you have setup.

    ReplyDelete
  4. I usually work off of windows authentication (the benefits of working on an intranet), so I never thought about this. That's a pretty good idea - I might try this on some of my side projects unfortunately I'll have to rewrite it for ruby :)

    You could also take the login code and put it in a separate class and add an if in your master page_init to load if you're on th dev machine

    ReplyDelete