Redirecting users based on group membership

Problem and solution overview

Ok, another forum request turned into a solution that hopefully will benefit a lot of you:

Here’s what I’m looking to do –

I have a site collection : http://>/sites/

I can place a DNS entry to direct http://MyTeamSite to http://>, but nothing after the /.

I’d like to point http://MyTeamSite to the full path.  Our DNS admin suggested using IIS to redirect the path, but so far I’ve not found a way to do so (I’m far from an IIS expert).

Does anyone have a suggestion as to how that could be accomplished?  We want to provide some level of abstraction for some of our team sites, plus allow us to shuffle things around a bit when necessary without disturbing the user’s links.

This sounds like a job for AnonymousRedirect! Unfortunately, it only redirects users based on anonymous logon so it won’t really do what we want.

What we want to do expand on the ideas from the AnonymousRedirect article and expand to allow for a lot more flexible redirection and configuration. A good idea then is to create a complex component that has sub classes used for configuration. That way we can create something along the lines of the following pseudo-code:


   
   

    …

We will work off this idea and see if we can solve the problem.

Walkthrough

Step 0: Setup

Start with your regular class library and set it up according to Basic setup of SharePoint Visual Studio project. I am calling my solution and thus namespace Redirector. I have also added two class files, called RedirectUsers.cs and UserMap.cs, with public classes named according to the file name. Finally I have added a reference to System.Web.dll.  To get you to this point I have uploaded a zipped Visual Studio 2005 solution, Redirector_Begin.zip, that you can download to save you a few minutes of setup.

Once you have built the solution once we need to add the dll to our safecontrols for the web application. Open your web.config, locate the SafeControls section and type in the following:

Note that your strong name (what is in Assembly) as well as namespace may be different for you. If in doubt, use .Net Reflector to get your strong name and Namespace.

You will also need to restart your web application to make sure the SafeControl entry is activated.

Step 1: UserMap class

Let’s start with the simplest class, UserMap. All this class will really do is hold the relationships between user groups and the URL to which users belonging to that group will be directed.

The UserMap class is included below. I will explain all relevant lines below the code.

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Text;
    4 using System.Web.UI;
    5 
    6 namespace Redirector
    7 {
    8     [ToolboxData("<{0}:UserMap runat=\"server\">")]
    9     public class UserMap : Control
   10     {
   11         private string m_Group;
   12 
   13         public string Group
   14         {
   15             get { return m_Group; }
   16             set { m_Group = value; }
   17         }
   18 
   19         private string m_Url;
   20 
   21         public string Url
   22         {
   23             get { return m_Url; }
   24           &
nbsp; set { m_Url = value; }
   25         }
   26 
   27     }
   28 }

Edit: If someone can explain to me why line spacing is doubled after this point, I would be very happy. I know that blogger puts two
tags here, but why do they do it just after this code block?

Right, that wasn’t so hard, was it?

Line 4 gives us simpler access to the System.Web.UI namespace so we can get the ToolboxData attribute decoration for our class.

Line 8 adds that ToolboxData decoration which just defines how our class should be used in markup. Note that this must match your class name or the control will not work.

Line 9 ensures we are inheriting from the Control class. Since we do not need any rendering we can inherit from Control rather than WebControl.

Lines 11-25 adds the properties we want to configure to map a user group to a URL.

Ok, simple enough, let’s move on.

Step 2: RedirectUsers class

The next class is a bit more complicated, but not much. The RedirectUsers class will take any number of UserMap classes passed as parameters and then determine which mapping, if any, fits the current user. This is where the logic will be.

Now, since the class will contain child controls, we need to treat it with some tender love and care to make sure it has all it needs to manage these controls. First, we need to make sure that we decorate our class with the ParseChildren attribute. I will take the simplest approach here, which at least in my opinion is to skip the ControlBuilder road. That means we should also create an ArrayList to hold the child controls. I will explain all this in a few moments.

Here is the code, and again I will explain the steps afterwards:

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Text;
    4 using System.Web.UI;
    5 using System.Collections;
    6 using System.Web;
    7 
    8 namespace Redirector
    9 {
   10     [ToolboxData("<{0}:RedirectUsers runat=\"server\">")]
   11     [ParseChildren(true, "UserMaps")]
   12     public class RedirectUsers : Control
   13     {
   14         private ArrayList m_UserMaps = new ArrayList();
   15 
   16         public ArrayList UserMaps
   17         {
   18             get { return m_UserMaps; }
   19         }
   20 
   21         protected override void OnLoad(EventArgs e)
   22         {
   23             foreach (UserMap userMap in UserMaps)
   24             {
   25                 if (HttpContext.Current.User.IsInRole(userMap.Group)) {
   26                     this.Page.Response.Redirect(userMap.Url, true);
   27                 }
   28             }
   29         }
   30     }
   31 }

Lines 1-6 are using statements, simple enough.

Line 10, as for UserMap, tells us how the class will be used.

Line 11 ParseChildren is what makes this class able to hold child controls and have them added to an ArrayList automatically. It tells ASP.net how child controls should be handled. In this case we are telling it that we should indeed parse the child controls as attributes to our control and that we want those child controls to be added to an ArrayList called UserMaps. I can elaborate on the use of ParseChildren in a later article but for now we keep it simple.

Line 12 makes sure our class inherits from the Control class.

Lines 14-10 sets up the property UserMaps that will be populated with the child controls for us. Note that the private field must be initialized (line 14).

Next, lines 21-29 overrides the OnLoad method to actually perform the redirect.

The foreach loop in lines 23-28 checks if the current user IsInRole of the userMap group property. We iterate through the child controls of the UserMaps ArrayList, assuming each entry is in fact a UserMap control. You should add some error handling here or improve on the ParseChildren attribute, but for now I will leave that as an exercise.

Finally, in line 26 we redirect the user to the URL of the UserMap control. Note that we add a ‘false’ boolean value to the Page.Response.Redirect. If you do not do this, Response.Redirect will throw an exception (ThreadAbortException) although the user will never see it. The last false value ensures that thread is not aborted after the Redirect, which is what we want in this case.

That’s it, code complete. Compile, build and we are ready to put this to the test.

Step 3: Deploy and test

Start your favorite ASP.net page editor. I’ll use SharePoint designer since I am in a SharePoint mood these days. Create a new page in the site you configured in the SafeControls part of step 1. Add the following to the top of your page:

<%@ Page Language="C#" %>
<%@ Assembly Name="Redirector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1665d9414c75603e" %>
<%@ Register TagPrefix="Furuknap" Assembly="Redirector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1665d9414c75603e" Namespace="Redirector" %>
 

 



 


 

 

You may need to change the strong name, and you would likely want to change the TagPrefix. You can add multiple UserMap tags to your code to test different user groups, of course.

Launch your page and, if you are a member of the Administrators group you will be redirected to whatever is in the corresponding Url property of that UserMap. I have included the entire solution, including a test aspx file, in a downloadable zip here.

You can put this component on any ASP.net page to implement the redirection. You might even consider putting it in a master page, but remember that every page that uses the master page will then redirect the user to the same Url.

And of course, very important, do not redirect _to_ a page containing the component as that would cause an infinite loop. You might want to implement some error handling to fix this, perhaps by setting a cookie or storing a value in viewstate.

Suggested improvements

Here are some suggestions you may want to implement to improve the redirector.

-We have made a redirector to check for groups. However, users can be members of several groups. Implement a ranking system so that you can create a tree of redirects. Hint: Expand the UserMap class with a priority property and sort the array before the foreach loop.

- This redirector only works for groups, or roles to be specific. How about improving the component by allowing redirection based on other criteria? Perhaps based on user name? In SharePoint you can redirect the user to his or her ‘Tasks overdue’ page if there are tasks overdue.

- You should add better error handling. This is a ‘get it to work, not scale and be stable’ solution to illustrate.

Be creative, and feel free to share any improvements.

That’s it, nothing more to see here. Feel free to respond to the poll below so I know if you like this stuff :-) Thank you!

Tags: , , ,

Post Author

This post was written by who has written 423 posts on Furuknap's SharePoint Corner.

I do SharePoint. When I'm not doing SharePoint, I sleep, and then I dream about SharePoint. Oh, and I dabble a bit in cryptocurrencies (Bitcoin, Litecoin, etc)

No comments yet.

Leave a Reply