Redirect a Login By Role in C# ASP .NET

modified

Introduction

Redirecting a user after login to a C# ASP .NET web application is a common feature found in most web applications. It’s also quite common to have multiple types of users logging into the ASP .NET web application, differing by the type of role membership they belong to, and each requiring a redirect to their specific landing page. While this can certainly be achieved with a couple of Response.Redirect() calls, you can create a much more robust automatic redirect-by-role solution.

This article describes how to automatically redirect users upon login, based upon their role membership. Since the list of redirect URLs may change frequently, we’ll store them conveniently within the web.config configuration file. New user roles and redirect URLs can be added without recompilation of the C# ASP .NET web application.

On First Thought, It Isn’t Pretty

When thinking about redirecting users after login, based upon their role, the first way of implementing this is to create a couple of if/then and Response.Redirect statements, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void btnLogin_Click(object sender, EventArgs e)
{
    //
    // Validate user, check login, create authentication ticket, populate roles, etc.
    // ...
    //

    if (Roles.IsUserInRole(txtUsername.Text, "User"))
    {
        Response.Redirect("~/User/");
    }
    else if (Roles.IsUserInRole(txtUsername.Text, "Administrator"))
    {
        Response.Redirect("~/Admin/");
    }
}

However, what happens when we need to add another login redirect to the system for a new role type? We would have to edit the if/then block, add a new conditional, and re-compile the web application. Eventually, this can create a mess. Consider the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected void btnLogin_Click(object sender, EventArgs e)
{
  //
  // Validate user, check login, create authentication ticket, populate roles, etc.
  // ...
  //

  if (Roles.IsUserInRole(txtUsername.Text, "User"))
  {
       Response.Redirect("~/User/");
  }
  else if (Roles.IsUserInRole(txtUsername.Text, "Administrator"))
  {
       Response.Redirect("~/Admin/");
  }
  else if (Roles.IsUserInRole(txtUsername.Text, "Tester"))
  {
       Response.Redirect("~/Tester/");
  }
  else if (Roles.IsUserInRole(txtUsername.Text, "Customer"))
  {
       Response.Redirect("~/Customer/");
  }
 else if (Roles.IsUserInRole(txtUsername.Text, "Client"))
{
      Response.Redirect("~/Client/");
}
else if (Roles.IsUserInRole(txtUsername.Text, "Manager"))
 {
     Response.Redirect("~/Cave/");
  }
  // ...
}

As you can tell, the list isn’t looking pretty. We can actually break this down into a much more clean system by pulling out the decision logic in the if/then statements and moving it to the web.config, where we can quickly and easily change it, without re-compiling or changing code.

Defining the Redirect URLs in the Web.Config

We’ll start off by defining the list of URLs that our users will be redirected to, based upon their role membership. The URLs will be listed in the web.config, for easy modification at a later time. This decouples the list of URLs from the web application source code and allows us to quickly add new roles and login redirects on the fly. The web.config redirect login block appears as follows:

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<configuration>
  <loginRedirectByRole>
    <roleRedirects>
      <add role="Administrator" url="~/Admin/" />
      <add role="User" url="~/User/" />
    </roleRedirects>
  </loginRedirectByRole>
</configuration>

Notice in the above web.config section, we’ve defined a custom section block named loginRedirectByRole. This block holds a list of roleRedirects. The roleRedirects list functions in the same way as adding connection strings to your web.config. In this manner, it should be extrememly easy to add and remove roles and login redirects.

Each item added to the roleRedirects list consists of a role name and a URL. In the example above, we’ve defined two roles: Administrator and User, which automatically redirect to their own landing page after login. It’s important to note that the redirected pages exist in their own sub-folders, separated by role. This is important so that you can create separate web.config files to restrict security to those folders by role. For example, the ~/User/ folder contains the following web.config file:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<configuration>
  <appSettings/>
  <connectionStrings/>
  <system.web>
    <authorization>
      <allow roles="User" />
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>

Only users who contain the role User will be allowed to access this folder. Similarly, the ~/Admin/ folder contains the following web.config file:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<configuration>
  <appSettings/>
  <connectionStrings/>
  <system.web>
    <authorization>
      <allow roles="Administrator" />
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>

Only users who contain the role Administrator will be allowed to access this folder. You could easily expand the roleRedirects list as requried, depending on the different user roles your ASP .NET web application may contain.

Since we’ve created a custom configuration section in the main web.config, we’ll also need to define the configuration section tag in the configSections area of your main web.config as follows:

1
2
3
 <configSections>
    <section name="loginRedirectByRole" type="WebApplication1.LoginRedirectByRoleSection" allowLocation="true" allowDefinition="Everywhere" />
 </configSections>

The changes we’ve made to the project’s main web.config file, thus far, would appear as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0"?>
<configuration>
   <configSections>
       <section name="loginRedirectByRole" type="WebApplication1.LoginRedirectByRoleSection" allowLocation="true" allowDefinition="Everywhere" />
    </configSections>

  <loginRedirectByRole>
    <roleRedirects>
      <add role="Administrator" url="~/Admin/" />
      <add role="User" url="~/User/" />
    </roleRedirects>
  </loginRedirectByRole>

  <appSettings>
  </appSettings>
  <connectionStrings>
  </connectionStrings>

  <!-- rest of web.config ... -->

</configuration>

We’ve now defined the web.config structure for holding the login redirect URLs. Next, we can move on to creating the code to handle it.

Reading the Login Redirect List with a Custom ConfigurationSection

With the web.config custom configuration section defined, we now need to create a custom configuration section reader class to obtain the list of login redirects and provide easy access. We can do this by creating the following class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class LoginRedirectByRoleSection : ConfigurationSection
{
[ConfigurationProperty("roleRedirects")]
    public RoleRedirectCollection RoleRedirects
    {
        get
        {
            return (RoleRedirectCollection)this["roleRedirects"];
        }
        set
        {
            this["roleRedirects"] = value;
        }
    }
}

public class RoleRedirectCollection : ConfigurationElementCollection
{
    public RoleRedirect this[int index]
    {
        get
        {
            return (RoleRedirect)BaseGet(index);
        }
    }

    public RoleRedirect this[object key]
    {
        get
        {
            return (RoleRedirect)BaseGet(key);
        }
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new RoleRedirect();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((RoleRedirect)element).Role;
    }
}

public class RoleRedirect : ConfigurationElement
{
    [ConfigurationProperty("role", IsRequired = true)]
    public string Role
    {
        get
        {
            return (string)this["role"];
        }
        set
        {
            this["role"] = value;
        }
    }

    [ConfigurationProperty("url", IsRequired = true)]
    public string Url
    {
        get
        {
            return (string)this["url"];
        }
        set
        {
            this["url"] = value;
        }
    }
}

Note the above code is a standard definition of a web.config custom configuration section. The structure follows that defined in the web.config. With this class defined, we’ll be able to access the roleRedirects list by calling myConfigSection.RoleRedirects.

The Key to Redirecting Logins by Role

We’ve completed the web.config declarations and have created the custom configuration section to read it. We can now create the actual method which determines the redirect page based upon the logged in user’s role.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <summary>
/// Redirect the user to a specific URL, as specified in the web.config, depending on their role.
/// If a user belongs to multiple roles, the first matching role in the web.config is used.
/// Prioritize the role list by listing higher-level roles at the top.
/// </summary>
/// <param name="username">Username to check the roles for</param>
private void RedirectLogin(string username)
{
    LoginRedirectByRoleSection roleRedirectSection = (LoginRedirectByRoleSection)ConfigurationManager.GetSection("loginRedirectByRole");
    foreach (RoleRedirect roleRedirect in roleRedirectSection.RoleRedirects)
    {
        if (Roles.IsUserInRole(username, roleRedirect.Role))
        {
            Response.Redirect(roleRedirect.Url);
        }
    }
}

The above code simply instantiates the custom configuration section to obtain the list of login redirect URLs. It then compares the currently logged-in user’s role to those listed in the web.config. When it locates a matching role, it redirects the user to the designated landing page. If a user happens to belong to more than one role, the user will be redirected to the first matching role’s landing page. In this manner, you can list higher priority roles at the top of the web.config list. For example, an Admin user can belong to the User role and the Administrator role, so that he can access both areas of the application. Since his role is listed first in the web.config, he’ll be redirected to the ~/Admin/ page, which is probably the expected landing page, even though he is also a member of the User role (which redirects to ~/User/).

Where to Call the Redirect Method Depends on What You’re Using

We’ve now completed the framework for automatically redirecting users, upon login, based upon their role. However, we still need to add the code which calls our RedirectLogin method. The location of this call depends on the type of login mechanism that you’re using.

The most common method of logging a user in is by using the standard ASP .NET Login control. When using the Login control, you’ll have a control tag as follows:

1
<asp:Login ID="ctlLogin" runat="server" RememberMeSet="True" DestinationPageUrl="~/User/" onloggedin="ctlLogin_LoggedIn">

Notice in the above code, we add a handler for the OnLoggedIn event. This allows us to know when the user has completed logging into the web application so that we can automatically redirect him to the proper landing page, as follows:

1
2
3
4
protected void ctlLogin_LoggedIn(object sender, EventArgs e)
{
    RedirectLogin(ctlLogin.UserName);
}

If you’re using your own login control you can utilize the same redirect function call, but placed within the area after you validate and create the authentication ticket cookie.

1
2
3
4
5
6
7
8
9
protected void btnLogin_Click(object sender, EventArgs e)
{
    //
    // Validate user, check login, create authentication ticket, populate roles, etc.
    // ...
    //

    RedirectLogin(txtUsername.Text);
}

In either case, after the user has been successfully logged in, and his roles have been populated, you can call the RedirectLogin() function, as shown above, to begin the redirect.

If you are using the standard ASP .NET Login control, you will need to also define a Membership Provider and a Role Provider, as found in this article.

Download complete project source code.

Conclusion

Redirecting users, upon login, based on their role can be as simple as adding a few if/then statements and a Response.Redirect call. However, by decoupling the decision logic from your C# ASP .NET web application code and moving it into the web.config, you can help create a much more efficient, robust, and extensible system. By separating user landing pages by sub-folder and restricting permissions by role, we can safely designate landing pages by role membership and help achieve a more seamless experience for the user.

About the Author

This article was written by Kory Becker, software developer and architect, skilled in a range of technologies, including web application development, machine learning, artificial intelligence, and data science.

Share