views:

628

answers:

2

I am using the following code from MVC Storefront to test OpenId in MVC. How do I integrate it with my ASP.Net Membership so I can use roles and save a user name for the user in my tables? I believe that SO is also using something similar.

    public ActionResult OpenIdLogin()
    {
        string returnUrl = VirtualPathUtility.ToAbsolute("~/");
        var openid = new OpenIdRelyingParty();
        var response = openid.GetResponse();
        if (response == null)
        {
            // Stage 2: user submitting Identifier
            Identifier id;
            if (Identifier.TryParse(Request["openid_identifier"], out id))
            {
                try
                {
                    IAuthenticationRequest req = openid.CreateRequest(Request["openid_identifier"]);

                    var fetch = new FetchRequest();
                    //ask for more info - the email address
                    var item = new AttributeRequest(WellKnownAttributes.Contact.Email);
                    item.IsRequired = true;
                    fetch.Attributes.Add(item);
                    req.AddExtension(fetch);

                    return req.RedirectingResponse.AsActionResult();
                }
                catch (ProtocolException ex)
                {
                    ViewData["Message"] = ex.Message;
                    return View("Logon");
                }
            }
            else
            {
                ViewData["Message"] = "Invalid identifier";
                return View("Logon");
            }
        }
        else
        {
            // Stage 3: OpenID Provider sending assertion response
            switch (response.Status)
            {
                case AuthenticationStatus.Authenticated:

                    var fetch = response.GetExtension<FetchResponse>();
                    string name = response.FriendlyIdentifierForDisplay;
                    if (fetch != null)
                    {
                        IList<string> emailAddresses = fetch.Attributes[WellKnownAttributes.Contact.Email].Values;
                        string email = emailAddresses.Count > 0 ? emailAddresses[0] : null;
                        //don't show the email - it's creepy. Just use the name of the email
                        name = email.Substring(0, email.IndexOf('@'));
                    }
                    else
                    {

                        name = name.Substring(0, name.IndexOf('.'));
                    }

                    //FormsAuthentication.SetAuthCookie(name, false);
                    SetCookies(name, name);
                    AuthAndRedirect(name, name);

                    if (!string.IsNullOrEmpty(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                case AuthenticationStatus.Canceled:
                    ViewData["Message"] = "Canceled at provider";
                    return View("Logon");
                case AuthenticationStatus.Failed:
                    ViewData["Message"] = response.Exception.Message;
                    return View("Logon");
            }
        }
        return new EmptyResult();

    }

    ActionResult AuthAndRedirect(string userName, string friendlyName)
    {
        string returnUrl = Request["ReturnUrl"];
        SetCookies(userName, friendlyName);

        if (!String.IsNullOrEmpty(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return RedirectToAction("Index", "Home");
        }
    }
+1  A: 

The open id provider will return data about the user. If you don't request/require specific tokens of information, then all you'll be given is the user's display name and identity URL.

Depending on what open id library you're using, you can request tokens like FirstName LastName, DOB (if you really cared) and if the user provided that information on their chosen identity, then you'd get it returned to you.

You can then use this to create a new user in the membership system. You'll probably have to give them a dummy password to get around the requirements of the Membership API.

To validate a login, provide 1 form that takes username & password and the other that takes an identity URL. After you've validated the user via open id, try to find the user by username (identity url) in the Membership API. If it doesn't exist, create it.

Ben Scheirman
+4  A: 

There are several questions like yours already on StackOverflow. This one seems particularly similar.

If you're already using the Membership provider for your site and are just adding OpenID to it, then I guess you're stuck with Membership for now and can use one of the answers to the question I linked to to get a semi-decent membership provider that MAY work for you.

But if you're writing a new site and just want "use roles and save a user name for the user in my tables" as you said, then DON'T use ASP.NET Membership at all. It's SO not worth it! It doesn't fit OpenID's password-less paradigm and just causes more grief than anything else. If you're not afraid of a little bit of database access yourself, do it that way. And you can get Roles behavior very easily by just issuing your own FormsAuthentication.RedirectFromLoginPage or FormsAuthentication.SetAuthCookie call and passing in the roles the user fills.

Andrew Arnott
I am playing around with a new implementation so, I am not particularly married to ASP.NET Membership. Can you suggest with sample code on how to do it the way you have mentioned?
Picflight
I'll leave a "me too" here for the sample code. Do you know of any?
Kenji Kina
All the samples and project templates that ship with DotNetOpenAuth do it the way I mentioned.
Andrew Arnott