ASP.NET MVC: Using ProfileRequiredAttribute to restrict access to pages

If you are using AppFabric Access Control Services to authenticate users when they log in to your community site using Live ID, Google or some other popular identity provider, you need more than AuthorizeAttribute to make sure that users can access the content that is there for authenticated users only. In this posting I will show you hot to extend the AuthorizeAttribute so users must also have user profile filled.

Semi-authorized users

When user is authenticated through external identity provider then not all identity providers give us user name or other information we ask users when they join with our site. What all identity providers have in common is unique ID that helps you identify the user.

Example. Users authenticated through Windows Live ID by AppFabric ACS have no name specified. Google’s identity provider is able to provide you with user name and e-mail address if user agrees to publish this information to you. They both give you unique ID of user when user is successfully authenticated in their service.

There is logical shift between ASP.NET and my site when considering user as authorized.

For ASP.NET MVC user is authorized when user has identity. For my site user is authorized when user has profile and row in my users table. Having profile means that user has unique username in my system and he or she is always identified by this username by other users.

Is user authorized?

My solution is simple: I created my own action filter attribute that makes sure if user has profile to access given method and if user has no profile then browser is redirected to join page.

Illustrating the problem

Usually we restrict access to page using AuthorizeAttribute. Code is something like this.

[Authorize]
public ActionResult Details(string
id)
{
   
var
profile = _userRepository.GetUserByUserName(id);
   
return View(profile);
}

If this page is only for site users and we have user profiles then all users – the ones that have profile and all the others that are just authenticated – can access the information. It is okay because all these users have successfully logged in in some service that is supported by AppFabric ACS.

In my site the users with no profile are in grey spot. They are on half way to be users because they have no username and profile on my site yet. So looking at the image above again we need something that adds profile existence condition to user-only content.

[ProfileRequired]
public ActionResult Details(string
id)
{
   
var
profile = _userRepository.GetUserByUserName(id);
   
return View(profile);
}

Now, this attribute will solve our problem as soon as we implement it.

ProfileRequiredAttribute: Profiles are required to be fully authorized

Here is my implementation of ProfileRequiredAttribute. It is pretty new and right now it is more like working draft but you can already play with it.

public class ProfileRequiredAttribute : AuthorizeAttribute
{
   
private readonly string
_redirectUrl;

   
public
ProfileRequiredAttribute()
    {
        _redirectUrl =
ConfigurationManager.AppSettings["JoinUrl"
];
       
if (string
.IsNullOrWhiteSpace(_redirectUrl))
            _redirectUrl =
"~/"
;
    }

   
public override void OnAuthorization(AuthorizationContext
filterContext)
    {
       
base
.OnAuthorization(filterContext);

       
var
httpContext = filterContext.HttpContext;
       
var
identity = httpContext.User.Identity;

       
if (!identity.IsAuthenticated || identity.GetProfile() == null
)
           
if (filterContext.Result == null)
                httpContext.Response.Redirect(_redirectUrl);
    }
}

All methods with this attribute work as follows:

  • if user is not authenticated then he or she is redirected to AppFabric ACS identity provider selection page,
  • if user is authenticated but has no profile then user is by default redirected to main page of site but if you have application setting with name JoinUrl then user is redirected to this URL.

First case is handled by AuthorizeAttribute and the second one is handled by custom logic in ProfileRequiredAttribute class.

GetProfile() extension method

To get user profile using less code in places where profiles are needed I wrote GetProfile() extension method for IIdentity interface. There are some more extension methods that read out user and identity provider identifier from claims and based on this information user profile is read from database. If you take this code with copy and paste I am sure it doesn’t work for you but you get the idea.

public static User GetProfile(this IIdentity identity)
{
   
if (identity == null
)
       
return null
;

   
var context = HttpContext
.Current;
   
if (context.Items["UserProfile"] != null
)
       
return context.Items["UserProfile"] as User
;

   
var
provider = identity.GetIdentityProvider();
   
var
nameId = identity.GetNameIdentifier();

   
var rep = ObjectFactory.GetInstance<IUserRepository
>();
   
var
profile = rep.GetUserByProviderAndNameId(provider, nameId);

    context.Items[
"UserProfile"
] = profile;

   
return profile;
}

To avoid round trips to database I cache user profile to current request because the chance that profile gets changed meanwhile is very minimal. The other reason is maybe more tricky – profile objects are coming from Entity Framework context and context has also HTTP request as lifecycle.

Conclusion

This posting gave you some ideas how to finish user profiles stuff when you use AppFabric ACS as external authentication provider. Although there was little shift between us and ASP.NET MVC with interpretation of “authorized” we were easily able to solve the problem by extending AuthorizeAttribute to get all our requirements fulfilled. We also write extension method for IIdentity that returns as user profile based on username and caches the profile in HTTP request scope.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    20 thoughts on “ASP.NET MVC: Using ProfileRequiredAttribute to restrict access to pages

    • February 20, 2013 at 5:36 pm
      Permalink

      Thanks you for your great posts. Helped me a lot to get around WIF and Live ID missing Name property.

    • Pingback:ASP.NET and WIF: Showing custom profile username as User.Identity.Name | Gunnar Peipman - Programming Blog

    • Pingback:ASP.NET MVC: How to implement invitation codes support | Gunnar Peipman - Programming Blog

    • February 2, 2016 at 1:49 am
      Permalink

      I too have a “Registered User without a profile problem”. However, before all the MS stuff the registration and profile where just one row in a table. (less secure but that is the past).

      So to get the user’s profile filled out because it’s info is used in my website, I built a SQL Server View on the database with the 2 tables, AspNetUsers, and “AccountProfile” left joined on AspNetUsers Id field. Now, user logs in and is directed to their “Account” page that has both. Or they can go to the menu and pick “Edit Profile”. In my personal need, this works dandy. when the call to the Controller to update profile with new or changed info, I just update the fields in “AccountProfile”. The SQL Server view server multiple purposed. I can just display public view of Accounts with limited information.

    • February 2, 2016 at 1:52 am
      Permalink

      The SQL Server view serves multiple purposes.
      Is what I was trying to type.

      public see only part of SQL Server View
      registered user sees also a limited display of all his compadres
      registered user can see his own profile and edit it.
      same SQL Sever View with different portions used.

    • April 4, 2025 at 12:45 am
      Permalink

      I have read so many articles or reviews about the blogger lovers except this
      article is genuinely a nice article, keep it up.

    • April 5, 2025 at 2:02 am
      Permalink

      These are truly great ideas in about blogging.
      You have touched some fastidious points here. Any way keep up wrinting.

    • April 5, 2025 at 10:56 pm
      Permalink

      With havin so much written content do you ever run into any issues
      of plagorism or copyright violation? My blog has a lot of unique content I’ve either authored myself or outsourced
      but it appears a lot of it is popping it up all over the internet without my authorization. Do
      you know any methods to help prevent content from being stolen? I’d
      really appreciate it.

    • April 6, 2025 at 5:21 am
      Permalink

      Thank you for another informative site. The place else may
      I am getting that kind of information written in such an ideal approach?
      I have a challenge that I’m just now working on, and I’ve been on the look out for such info.

    • April 6, 2025 at 3:24 pm
      Permalink

      I was excited to uncover this page. I want to to thank you for your time for this
      particularly fantastic read!! I definitely liked every
      bit of it and i also have you saved to fav to look at new information on your website.

    • April 10, 2025 at 2:37 am
      Permalink

      It’s really a nice and useful piece of info.
      I am satisfied that you just shared this helpful info with
      us. Please keep us up to date like this. Thank you for sharing.

    • April 21, 2025 at 11:37 am
      Permalink

      Hmm it appears like your blog ate my first comment (it was super long) so I guess I’ll just sum
      it up what I wrote and say, I’m thoroughly enjoying your blog.
      I too am an aspiring blog writer but I’m still new to everything.
      Do you have any helpful hints for rookie blog writers?
      I’d genuinely appreciate it.

    • April 25, 2025 at 8:20 am
      Permalink

      I’m really enjoying the design and layout of your website.
      It’s a very easy on the eyes which makes it much more pleasant for
      me to come here and visit more often. Did you hire out a designer to
      create your theme? Great work!

    • April 30, 2025 at 10:10 pm
      Permalink

      If you would like to improve your experience simply keep visiting this site and be updated
      with the most recent gossip posted here.

    • May 8, 2025 at 2:54 pm
      Permalink

      Hi would you mind letting me know which hosting company you’re using?

      I’ve loaded your blog in 3 different browsers and I must say this blog loads a lot quicker
      then most. Can you suggest a good web hosting provider at a
      fair price? Cheers, I appreciate it!

    • May 8, 2025 at 7:05 pm
      Permalink

      I’m more than happy to discover this page. I want
      to to thank you for your time just for this fqntastic read!!
      I definitely appreciated every bit of it and i also have you bookmarked
      to see new things in your web site.

    • May 11, 2025 at 10:27 pm
      Permalink

      Hey just wanted to give you a quick heads up. The text in your article seem to be running off the screen in Internet explorer.

      I’m not sure if this is a format issue or something to do with web browser compatibility but I figured I’d post to let you
      know. The style and design look great though! Hope you
      get the problem fixed soon. Cheers

    • May 14, 2025 at 3:35 pm
      Permalink

      I am extremely impressed together with your writing abilities as smartly as with the format on your weblog.
      Is that this a paid topic or did you modify it your self?
      Either way stay up the excellent high quality writing, it’s uncommon to peer a nice weblog
      like this one today..

    • June 9, 2025 at 3:21 am
      Permalink

      Amazing blog! Is your theme custom made or did you download
      it from somewhere? A design like yours with a few simple adjustements would really make my blog shine.

      Please let me know where you got your design. Bless you

    Leave a Reply

    Your email address will not be published. Required fields are marked *