Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Keith Clegg 3 posts 53 karma points
    Nov 17, 2016 @ 19:54
    Keith Clegg
    0

    Accessing HttpContext from within a customised (extended) MembersRoleProvider class

    Hi all,

    I have a question in regards to accessing the HttpContext from within an extended MembersRoleProvider class.

    I'll give some background first:

    To allow me to authenticate against a separate system / database rather than standard Umbraco backend users, I have bypassed the Umbraco membership login / authentication by extending both the UsersMembershipProvider & MembersRoleProvider classes (along with changing the UmbracoMembershipProvider and UmbracoRoleProvider keys of the Web.Config so it makes use of these extended classes). This is based roughly on Umbraco 7 Custom Membership and Role Providers, and it is all working well.

    To allow me to return a little more than just the normal MembershipUser info, I have also (within the extended UsersMembershipProvider class) extended the MembershipUser class (which is what gets returned by GetUser method). It returns a few additional parameters to what it usually would when authenticating (being additional parameters which are essentially roles defined within the separate system / database and which are to get used for displaying / hiding certain pages within the site - or occasionally a section of the site such as on the home page). Having done this, it allows me to obtain these additional parameters from within my SignInController (by calling this GetUser method of the custom Membership Provider), and after which I then add these parameters as Session variables (for accessing them elsewhere later):

    Finally, to tie the roles from the separate system / database to the Umbraco backend, I have (within the Umbraco back office) created Member Groups that each correlate to one of these aforementioned roles (parameters) obtained from the separate system, i.e. these can get linked to a content page created in the back office by using the Public Access / Role Based Protection option in the backoffice to apply role based protection to the page and all its children), and within the string [] GetRolesForUser method of my extended MembersRoleProvider I return a string of roles corresponding to the just mentioned ones in existence in the Umbraco backend.

    Here lies the problem. In order to establish which roles to return within this string [] GetRolesForUser method I'd like to be able to access my session variables which would already have been set earlier when having authenticated, e.g. HttpContext.Current.Session["roleparam1"] etc, however I am unable to work out how to access the HTTP Context from here (from within my extended MembersRoleProvider class)? When I try HttpContext.Current is null.

    I am able obtain the roles / parameters once again by directly calling a method I exposed within the extended UsersMembershipProvider class (which in turn just calls the GetUser method within the UsersMembershipProvider class once again), however it does result in unnecessary hits on the database, since (as example) every time I make use of @if (Members.IsLoggedIn()) within a cshtml template (a View), the string [] GetRolesForUser method of the extended MembersRoleProvider gets invoked. Rather than hit the database each time this is invoked I'd much rather just poll this information I have already obtained and saved into the HTTP Context as session variables.

    Below is my string [] GetRolesForUser method (GetVSPlatUser is just a method I exposed within my custom UsersMembershipProvider class - which I use also during initial authentication initiated from my SignInController code to obtain the additional parameters):

    public override string[] GetRolesForUser(string username)
    {
        StringCollection CollectionOfRolesForUser = new StringCollection();
    
        //Unnecessary call to method in UsersMembershipProvider just in order to obtain roles (taking into account they'd already be set as session variables)
        PlatinumMembershipUser platinumMembershipUser = PlatinumUserHelperFunctions.GetVSPlatUser(username);
    
        if (platinumMembershipUser.HasRegisteredCardForAuWHV)
            CollectionOfRolesForUser.Add("Australia");
    
        if (platinumMembershipUser.HasRegisteredCardForNzWHV)
            CollectionOfRolesForUser.Add("New Zealand");
    
        // What I'd ideally want to be able to do
        //if (HttpContext.Current.Session["Has_Registered_Card_ForAuWHV"] != null)
        //    if (((bool)(HttpContext.Current.Session["Has_Registered_Card_ForAuWHV"]) == true))
        //        CollectionOfRolesForUser.Add("Australia");
    
        //if (HttpContext.Current.Session["Has_Registered_Card_ForNzWHV"] != null)
        //    if (((bool)(HttpContext.Current.Session["Has_Registered_Card_ForNzWHV"]) == true))
        //        CollectionOfRolesForUser.Add("New Zealand");
    
        string[] ArrayOfRolesForUser = new string[CollectionOfRolesForUser.Count];
        CollectionOfRolesForUser.CopyTo(ArrayOfRolesForUser, 0);
    
        return ArrayOfRolesForUser;
    
    }
    

    My SignInController code:

    public class SignInController : SurfaceController
    {
    
        public ActionResult SignIn(SignInModel model)
        {
            if (!ModelState.IsValid)
            {
                Members.Logout();
                Session.Clear();
                return CurrentUmbracoPage();
            }
    
            CustomMembershipProvider custMemProvider = new CustomMembershipProvider();
    
            //if we can login ok redirect to page
            if (Members.Login(model.EmailAddress, model.Password))
            {
                PlatinumMembershipUser platUser = custMemProvider.GetUser(model.EmailAddress);
    
                //Set Session variables
                System.Web.HttpContext.Current.Session["Has_Registered_Card_ForAuWHV"] = platUser.HasRegisteredCardForAuWHV;
                System.Web.HttpContext.Current.Session["Has_Registered_Card_ForNzWHV"] = platUser.HasRegisteredCardForNzWHV;
    
                // Just mucking about but this is not required as occurs automatically during custMemProvider.GetUser
                //custMemProvider.ValidateUser(model.EmailAddress, model.Password);
    
                if ((CurrentPage.Url == "/") || (CurrentPage.Url == "/home/" ) || (CurrentPage.Url == "/contact/"))
                {
                    if (platUser.HasRegisteredCardForAuWHV)
                    {
                        return Redirect("/australia");
                    }
                    else if (platUser.HasRegisteredCardForNzWHV)
                    {
                        return Redirect("/new-zealand");
                    }
                    else
                    {
                        return Redirect("/home");
                    }
                }
                else
                {
                    return RedirectToCurrentUmbracoPage();
                }
    
            }
            else
            {
                ModelState.AddModelError("", "Invalid Login");
    
                if (Members.IsLoggedIn())
                {
                    Members.Logout();
                }
    
                Session.Clear();
                return Redirect("/home");
    
            }
        }
    
        public ActionResult SignOut()
        {
            Members.Logout();
            Session.Clear();
            return Redirect("/home");
        }
    
    }
    

    Sorry for the long writeup of the background related to my question, but I didn't want to ask the question without it making some sense why I am asking it.

    I am hoping there is something simple I am missing whereby I could access my already set Session variables (set at time of authenticating), so that I don't end up having to hit the database every time the string [] GetRolesForUser method gets invoked (every time the roles for the user gets requested and returned), so if anyone can steer me to what I may be overlooking that would be tremendously appreciated.

    This is an Umbraco version 7.5.4 site.

    Regards,

    Keith

  • John Hesman 8 posts 99 karma points
    Nov 23, 2016 @ 14:36
    John Hesman
    0

    In similar situations I will pass in the HttpContext from the calling object.

    This would change the signature of your GetRolesForUser method to something like

    public override string[] GetRolesForUser(string username, HttpContextBase httpContext)
    

    which you can then use like

    httpContext.Session["yourSessionVariable"]
    

    You would then call the method like this

    var roles = GetRolesForUser(username, new HttpContextWrapper(HttpContext.Current));
    
Please Sign in or register to post replies

Write your reply to:

Draft