Search code examples
c#asp.net-mvc-3authorizationmembership

ASP.Net MVC 3 First login / complete profile


I am using the FormsAuthenticationService along with AccountMembershipService to handle membership and log in. I need a way to force a user to complete their profile when they log into the site, or go to a area that requires [Authorize()], before being able to continue on the site.

I was thinking about using a GlobalFilter on the AuthorizationContext but not sure if this would work as required.

Any ideas?


Solution

  • Following a bit of digging about I managed to find a way to achieve this.

    First created a global filter

    using System.Web.Mvc;
    using Microsoft.Practices.Unity;
    
    public sealed class LogOnAuthorize :  AuthorizeAttribute
    {
    
    [Dependency]
    public Service.IDaoService dao { get; set; }
    
    
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        string SessionKey = "ProfileCompleted";
    
        bool Authorization = filterContext.ActionDescriptor.IsDefined(typeof(AuthorizeAttribute), true)
            || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AuthorizeAttribute), true);
        bool ContainsIgnore = filterContext.ActionDescriptor.IsDefined(typeof(IgnoreCompleteProfileAttribute), true)
            || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(IgnoreCompleteProfileAttribute), true);
    
        if ((Authorization) && (!ContainsIgnore))
        {
            var ctx = System.Web.HttpContext.Current;
            if (ctx != null)
            {
                if (filterContext.HttpContext.User.Identity.IsAuthenticated) 
                {
                    if (ctx.Session[SessionKey] == null)
                    {
                        Models.UserDetail user = dao.UserDao.GetByEmail(filterContext.HttpContext.User.Identity.Name);
                        if (user != null)
                            ctx.Session[SessionKey] = user.CompletedAccount;
                    }
                    bool ForceRedirect = ((ctx.Session[SessionKey] == null) || ((bool)ctx.Session[SessionKey] == false));
                    string ReturnUrl = string.Empty;
    
                    if ((filterContext.HttpContext.Request != null) && (!string.IsNullOrEmpty(filterContext.HttpContext.Request.RawUrl)))
                        ReturnUrl = filterContext.HttpContext.Request.RawUrl.ToString();
    
                    if (ForceRedirect)
                        filterContext.Result = new RedirectToRouteResult("CompleteAccount", new System.Web.Routing.RouteValueDictionary {  {"ReturnUrl" , ReturnUrl} });
                }
                else
                    base.OnAuthorization(filterContext);
            }
            else
                base.OnAuthorization(filterContext);
        }
    }
    }
    

    Then registed it up in the global.asax.cs

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new LogOnAuthorize());
    
        }
    

    For any actions that I needed to be authorised but not perform the check on I used

    [Authorize()]
    [IgnoreCompleteProfileAttribute()]
    public ActionResult LogOff()
    {
        // Code Here
    }
    

    Which used this class

    using System;
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class IgnoreCompleteProfileAttribute : Attribute { }
    

    Which all works well for what I needed, hope this helps someone.