Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Probably I'm too late, but I came into this problem some days ago and I found only few poor solutions on the web. So I wrote my own solution and I can post it only now.</p> <p>I took advantage of the DotNetOpenAuth.AspNet.Clients.OAuth2Client class which do the most of the job. I only extended that to include scope and extra user data.</p> <pre><code>public class FacebookExtendedClient : DotNetOpenAuth.AspNet.Clients.OAuth2Client { protected FacebookClient facebookClient; protected string fields; protected string scope; protected Func&lt;string, object, string&gt; fieldTransformer; protected bool emailAsUsername; protected IDictionary&lt;string, string&gt; userData; private string[] splittedFields; private string[] splittedScope; protected const string serviceLoginBaseUrl = "https://www.facebook.com/dialog/oauth"; protected const string serviceMeBaseUrl = "https://graph.facebook.com/me"; protected const string serviceAccessTokenBaseUrl = "https://graph.facebook.com/oauth/access_token"; /// &lt;summary&gt; /// Create an instrance of the class. /// &lt;/summary&gt; /// &lt;param name="appId"&gt;The App ID of the application used to connect to Facebook service.&lt;/param&gt; /// &lt;param name="appSecret"&gt;The App Secret of the application used to connect to Facebook service.&lt;/param&gt; /// &lt;param name="fields"&gt; /// String containing comma separated fields to add to the request. /// If empty the request will retrieve the default fields based of the specified scope. /// &lt;/param&gt; /// &lt;param name="fieldTransformer"&gt; /// Function to be applied to the values retrived from facebook. /// If null provided the method will try to cast values from object to string explicitly, /// an InvalidCastException will be thrown if the cast will not be possible. /// &lt;/param&gt; /// &lt;param name="scope"&gt; /// String containing comma separated permissions to add to the request. /// If empty the request will have the basic scope. /// &lt;/param&gt; /// &lt;param name="emailAsUsername"&gt;Makes the email of the facebook user used as authentication username.&lt;/param&gt; public FacebookExtendedClient(string appId, string appSecret, string fields = "", Func&lt;string, object, string&gt; fieldTransformer = null, string scope = "", bool emailAsUsername = false) : base("facebook") { if (string.IsNullOrEmpty(appId)) throw new ArgumentException("The appId argument can not be null or empty.", "appId"); if (string.IsNullOrEmpty(appSecret)) throw new ArgumentException("The appSecret argument can not be null or empty.", "appSecret"); fields = fields.Replace(" ", ""); scope = scope.Replace(" ", ""); this.splittedFields = fields.Split(','); this.splittedScope = scope.Split(','); if (emailAsUsername == true &amp;&amp; !this.splittedFields.Contains("email") &amp;&amp; !this.splittedScope.Contains("email")) throw new ArgumentException("The scope argument must contain the 'email' permission and the 'email' field to allow emailAsUsername to true.", "scope"); this.facebookClient = new FacebookClient(); this.facebookClient.AppId = appId; this.facebookClient.AppSecret = appSecret; this.fields = fields; this.fieldTransformer = fieldTransformer; this.scope = scope; this.emailAsUsername = emailAsUsername; } public FacebookClient FacebookClient { get { return this.facebookClient; } } public IDictionary&lt;string, string&gt; UserData { get { return this.userData; } } protected override Uri GetServiceLoginUrl(Uri returnUrl) { Dictionary&lt;string, object&gt; parameters = new Dictionary&lt;string, object&gt;(); parameters.Add("redirect_uri", returnUrl.AbsoluteUri); if (!string.IsNullOrEmpty(this.scope)) parameters.Add("scope", this.scope); return this.facebookClient.GetLoginUrl(parameters); } protected override IDictionary&lt;string, string&gt; GetUserData(string accessToken) { // This method makes the AuthenticationResult's UserName property be the facebook username of the logged user, // but if the facebook username is missing the facebook id will be used. // If emailAsUsername is true then AuthenticationResult's UserName property is the email retrieved from facebook // and the facebook username can be retrieved by the key "fb_username" in this.userData FacebookClient facebookClient = new FacebookClient(accessToken); var getResult = facebookClient.Get&lt;IDictionary&lt;string, object&gt;&gt;("me", new { fields = this.fields }); Dictionary&lt;string, string&gt; result = new Dictionary&lt;string, string&gt;(); if (this.fieldTransformer != null) { foreach (var pair in getResult) result.Add(pair.Key, this.fieldTransformer(pair.Key, pair.Value)); } else { foreach (var pair in getResult) { string value = pair.Value.ToString(); if (value == null) throw new InvalidCastException("Cast not possible for the object associate to the key '" + pair.Key + "'."); result.Add(pair.Key, value); } } if (this.splittedFields.Contains("username")) result["fb_username"] = result["username"]; if (this.emailAsUsername) result["username"] = result["email"]; this.userData = result; return result; } protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) { UriBuilder builder = new UriBuilder(serviceAccessTokenBaseUrl); builder.Query = string.Format("client_id={0}&amp;client_secret={1}&amp;redirect_uri={2}&amp;code={3}", this.facebookClient.AppId, this.facebookClient.AppSecret, HttpUtility.UrlEncode(Encoding.ASCII.GetBytes(returnUrl.AbsoluteUri)), authorizationCode); using (WebClient client = new WebClient()) { string str = client.DownloadString(builder.Uri); if (string.IsNullOrEmpty(str)) return null; return HttpUtility.ParseQueryString(str)["access_token"]; } } } </code></pre> <p>You can use it as well registering it in OAuthWebSecurity like this (put RegisterAuth method in Application_Start, like it is in the InternetApplication template):</p> <pre><code>public static class AuthConfig { public static void RegisterAuth() { configuration.LoadFromAppSettings(); OAuthWebSecurity.RegisterClient(new FacebookExtendedClient( "##YOUR_APP_ID##", "##YOUR_APP_SECRET##", "id,first_name,last_name,link,username,gender,email,age_range,picture.height(200)", new Func&lt;string, object, string&gt;(fieldsTransformer), "email")); } private static string fieldsTransformer(string key, object value) { switch (key) { case "picture": var data = (value as IDictionary&lt;string, object&gt;)["data"] as IDictionary&lt;string, object&gt;; return data["url"].ToString(); case "age_range": var min = (value as IDictionary&lt;string, object&gt;)["min"]; return min.ToString(); default: return value.ToString(); } } } </code></pre> <p>As you can see in the example above the method fieldsTransformer will get the key and the value foreach field selected, in this case it will transform the object retrived by facebook for the picture into the url of the picture. This is a convenience method, if null is provided for the Func parameter, the JSON representation of the values object will be saved.</p> <p>Retrieve the client information later, after the login, can be done like this:</p> <pre><code>[Authorize] public class HomeController : Controller { public ActionResult Index() { IDictionary&lt;string, string&gt; userData = (OAuthWebSecurity.GetOAuthClientData("facebook").AuthenticationClient as FacebookExtendedClient).UserData; string email = userData["email"]; // If leave null the fieldTransform of the client you can access to complex properties like this: JObject picture = JObject.Parse(userData["picture"]); string url = (picture["data"] as JObject)["url"].ToString(); ViewBag.Email = userData["email"]; ViewBag.PictureUrl = url; return View(); } } </code></pre> <p>Hope you enjoy this code, even if it is a bit late! :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload