2012-09-26 11 views
6

Utilizzando la nuova OAuthWebSecurity per l'autenticazione con Facebook, ho aggiunto il permesso di posta elettronica sulla mia applicazione di Facebook. Ora, come posso leggere, ho bisogno di definire un ambito per essere in grado di ottenere effettivamente l'e-mail nel risultato. Finora senza lo scopo non ricevo l'email degli utenti e non sono sicuro del perché non riesco a vedere dove definire lo "scope".OAuthWebSecurity con Facebook che non utilizza il permesso di posta elettronica come previsto

È solo uno strappo del ASP.NET MVC accesso di login per 4 controller di autenticazione predefiniti.

+0

Forse questo aiuta: http://blogs.msdn.com/b/webdev/archive/2012/08/23/plugging-custom-oauth-openid-providers.aspx – CBroe

risposta

0

Ho affrontato lo stesso problema qui. L'unico modo in cui ho trovato di passare il parametro "scope" a Facebook era la codifica del mio client OAuth.

Per farlo, è necessario estendere e implementare i metodi astratti di DotNetOpenAuth.AspNet.Clients.OAuth2Client.

Nel metodo GetServiceLoginUrl è possibile aggiungere il parametro scope all'URL. Pertanto, quando si chiama il metodo OAuthWebSecurity.VerifyAuthentication(), AuthenticationResult.UserName fornisce l'e-mail dell'utente.

Un esempio può essere trovato here.

Buona fortuna.

+0

Bene ora ho guardato ancora una volta il metodo per registrare facebook e ha un sovraccarico che richiede qualche parametro extraData, ma è questo per il login? IDictionary fbParams = new Dictionary (); fbParams.Add ("scope", "email"); OAuthWebSecurity.RegisterFacebookClient ("onekey", "anotherkey", "facebook", fbParams); –

+0

L'ho provato. Ma OAuthWebSecurity è stato ignorato. Lavorato per voi? –

+0

Non sarebbe stato premuroso ... sembra uno spreco non abilitare dichiarazioni "extraData" in questo modo. Mi chiedo quale fosse il ragionamento per non farlo in quel modo. –

21

In primo luogo, il parametro extraData non viene passato a Facebook. È solo per uso interno. Vedere il seguente link su come questi dati possono essere utilizzati sul tuo sito:

http://blogs.msdn.com/b/pranav_rastogi/archive/2012/08/24/customizing-the-login-ui-when-using-oauth-openid.aspx

Ora, per la carne:

Oltre ai metodi RegisterFacebookClient, RegisterYahooClient ecc OAuthWebSecurity, c'è anche un metodo generico RegisterClient. Questo è il metodo che useremo per questa soluzione.

Questa idea germina dal codice fornito al: http://mvc4beginner.com/Sample-Code/Facebook-Twitter/MVC-4-oAuth-Facebook-Login-EMail-Problem-Solved.html

Tuttavia, non useremo l'approccio hacky fornito dalla soluzione. Invece, creeremo una nuova classe chiamata FacebookScopedClient che implementerà IAuthenticationClient. Poi ci sarà semplicemente registrare la classe utilizzando:

OAuthWebSecurity.RegisterClient(new FacebookScopedClient("your_app_id", "your_app_secret"), "Facebook", null); 

in AuthConfig.cs

Il codice per la classe è:

using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Web; 

    public class FacebookScopedClient : IAuthenticationClient 
     { 
      private string appId; 
      private string appSecret; 

      private const string baseUrl = "https://www.facebook.com/dialog/oauth?client_id="; 
      public const string graphApiToken = "https://graph.facebook.com/oauth/access_token?"; 
      public const string graphApiMe = "https://graph.facebook.com/me?"; 


      private static string GetHTML(string URL) 
      { 
       string connectionString = URL; 

       try 
       { 
        System.Net.HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(connectionString); 
        myRequest.Credentials = CredentialCache.DefaultCredentials; 
        //// Get the response 
        WebResponse webResponse = myRequest.GetResponse(); 
        Stream respStream = webResponse.GetResponseStream(); 
        //// 
        StreamReader ioStream = new StreamReader(respStream); 
        string pageContent = ioStream.ReadToEnd(); 
        //// Close streams 
        ioStream.Close(); 
        respStream.Close(); 
        return pageContent; 
       } 
       catch (Exception) 
       { 
       } 
       return null; 
      } 

      private IDictionary<string, string> GetUserData(string accessCode, string redirectURI) 
      { 

       string token = GetHTML(graphApiToken + "client_id=" + appId + "&redirect_uri=" + HttpUtility.UrlEncode(redirectURI) + "&client_secret=" + appSecret + "&code=" + accessCode); 
       if (token == null || token == "") 
       { 
        return null; 
       } 
       string data = GetHTML(graphApiMe + "fields=id,name,email,gender,link&access_token=" + token.Substring("access_token=", "&")); 

       // this dictionary must contains 
       Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); 
       return userData; 
      } 

      public FacebookScopedClient(string appId, string appSecret) 
      { 
       this.appId = appId; 
       this.appSecret = appSecret; 
      } 

      public string ProviderName 
      { 
       get { return "Facebook"; } 
      } 

      public void RequestAuthentication(System.Web.HttpContextBase context, Uri returnUrl) 
      { 
       string url = baseUrl + appId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=email"; 
       context.Response.Redirect(url); 
      } 

      public AuthenticationResult VerifyAuthentication(System.Web.HttpContextBase context) 
      { 
       string code = context.Request.QueryString["code"]; 

       string rawUrl = context.Request.Url.OriginalString; 
       //From this we need to remove code portion 
       rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", ""); 

       IDictionary<string, string> userData = GetUserData(code, rawUrl); 

       if (userData == null) 
        return new AuthenticationResult(false, ProviderName, null, null, null); 

       string id = userData["id"]; 
       string username = userData["email"]; 
       userData.Remove("id"); 
       userData.Remove("email"); 

       AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData); 
       return result; 
      } 
     } 

ora nel metodo

public ActionResult ExternalLoginCallback(string returnUrl) 

in AccountController, result.ExtraData dovrebbe avere l'email.

Modifica: Ho perso un po 'di codice in questo post. Io sono l'aggiunta qui sotto:

public static class String 
    { 
     public static string Substring(this string str, string StartString, string EndString) 
     { 
      if (str.Contains(StartString)) 
      { 
       int iStart = str.IndexOf(StartString) + StartString.Length; 
       int iEnd = str.IndexOf(EndString, iStart); 
       return str.Substring(iStart, (iEnd - iStart)); 
      } 
      return null; 
     } 
    } 

Cheers!

+0

Ho riscontrato un problema con la riga "token.Substring (" access_token = "," & "))", poiché la sottostringa accetta solo numeri interi, ma questo ha aiutato immensamente. Ho deciso di scrivere un post sul blog spiegando come estendere ulteriormente questo aspetto, ma questo post mi ha ottenuto il 98%. http://savvydev.com/authenticating-facebook-users-with-mvc-4-oauth-and-obtaining-scope-permissions/ – MattSavage

+0

Scuse.Ho dimenticato di includere la classe di estensione per la stringa. Aggiungendolo al codice ora ..... –

+0

Grazie, Varun. Ho dovuto fare un piccolo ritocco per le app ospitate su AppHarbor (che spiego in [un'altra risposta] (http://stackoverflow.com/a/14567037/389899) ma hai fatto tutto il duro lavoro. – blachniet

13

Aggiorna il tuo pacchetto NuGet nel tuo progetto Internet MVC4.

DotNetOpenAuthCore. Aggiorna automaticamente tutte le dipendenze.

Ora result.UserName conterrà l'indirizzo e-mail anziché il proprio nome.

[AllowAnonymous] 
    public ActionResult ExternalLoginCallback(string returnUrl) 
    { 
     AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl })); 
     if (!result.IsSuccessful) 
     { 
      return RedirectToAction("ExternalLoginFailure"); 
     } 

     if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false)) 
     { 
      return RedirectToLocal(returnUrl); 
     } 

     if (User.Identity.IsAuthenticated) 
     { 
      // If the current user is logged in add the new account 
      OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name); 
      return RedirectToLocal(returnUrl); 
     } 
     else 
     { 
      // User is new, ask for their desired membership name 
      string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId); 
      ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName; 
      ViewBag.ReturnUrl = returnUrl; 
      return View("ExternalLoginConfirmation", new RegisterExternalLoginModel { UserName = result.UserName, ExternalLoginData = loginData }); 
     } 
    } 

Il motivo?

https://github.com/AArnott/dotnetopenid/blob/a9d2443ee1a35f13c528cce35b5096abae7128f4/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookClient.cs è stato aggiornato nell'ultimo pacchetto NuGet.

La impegnarsi con la correzione: https://github.com/AArnott/dotnetopenid/commit/a9d2443ee1a35f13c528cce35b5096abae7128f4

+1

Questo è grande :) molte grazie, che mi ha salvato tempo e lo sforzo per averlo personalizzato, è ora lo costruirono come dovrebbe essere;) – Shadi

+0

@PUssInBoots. Grandi istruzioni Li ho seguiti e sto ottenendo una e-mail di nuovo, tranne che è la società '[email protected].facebook.com' che non è quello che voglio. Qualche idea sul perché sto ricevendo questo lungo indirizzo proxymail.facebook.com? – user576838

+0

@ user576838 Non ho mai visto quel tipo di email nella mia app prima. Forse prova ad accedere con un altro utente con un'altra email da un altro provider di posta elettronica, vedi se ottieni gli stessi risultati. – PussInBoots

2

ho usato Varun's answer, ma ho dovuto fare una piccola modifica per farlo funzionare per la mia app essere ospitato su AppHarbor.

AppHarbor deve fare alcune cose funky con il numero di porta in urls per gestire il bilanciamento del carico. Puoi leggere un po 'di più su di esso here. In breve, ottenere l'AbsoluteUri dalla richiesta corrente durante l'hosting su AppHarbor può restituire un uri con un numero di porta diverso da 80. Ciò causa problemi con l'autenticazione di Facebook, poiché si aspetta che l'URL di ritorno sia quello specificato durante la creazione dell'app.

Il problema si verifica allo string rawUrl = context.Request.Url.OriginalString; in VerifyAuthentication(). Se si utilizza questo codice, rawUrl potrebbe contenere un numero di porta diverso da 80, causando il fallimento dell'autenticazione di Facebook. Invece, sostituire quella linea con

string rawUrl = GetRawUrl(context.Request.Url); 

e aggiungere la funzione GetRawUrl() alla classe:

public static string GetRawUrl(Uri url) 
{ 
    var port = url.Port; 
    if (SettingsHelper.GetHostingService() == HostingServices.AppHarbor) 
     port = 80; 

    return new UriBuilder(url) 
    { 
     Port = port 
    }.Uri.AbsoluteUri; 
} 

Sarà necessario sostituire il if (SettingsHelper.GetHostingService() == HostingServices.AppHarbor) con la propria logica per determinare se l'applicazione è in esecuzione su AppHarbor .

-2

Si può fare ... in questo modo:

var fb = new Dictionary<string, object>(); 
fb.Add("scope", "email,publish_actions"); 
OAuthWebSecurity.RegisterFacebookClient(
appId: ConfigurationManager.AppSettings["FacebookAppId"], 
appSecret: ConfigurationManager.AppSettings["FacebookAppSecret"], 
displayName: "FaceBook", 
extraData: fb); 
+1

Questo sembra molto plausibile. Ma non ha funzionato per me. – elif

+1

Questo non funziona. Il parametro "extraData" non viene inviato o utilizzato da Facebook. –

1

ho scritto la mia soluzione a questo problema. Ho esteso OAuth2Client per sfruttarne il funzionamento e utilizzato l'ambito Facebook e altre funzionalità per recuperare ulteriori dati utente. Ho pubblicato la mia soluzione here, spero che possa aiutare qualcuno!

Problemi correlati