6

Facebook での認証に新しい OAuthWebSecurity を使用して、Facebook アプリケーションに電子メールのアクセス許可を追加しました。今、私が読​​むことができるように、結果で実際に電子メールを取得できるようにスコープを定義する必要があります。これまでのところ、スコープがないと、ユーザーの電子メールを取得できません。「スコープ」を定義する場所がわからないため、理由がわかりません。

これは、 ASP.NET MVC 4 の既定の authenticationcontrollers 外部ログインのほんの一部です。

4

7 に答える 7

21

まず、extraData パラメータが facebook に渡されません。内部使用のみです。サイトでこのデータを使用する方法については、次のリンクを参照してください。

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

さて、肉に:

のメソッドなどにRegisterFacebookClient加えて、一般的なメソッドもあります。これは、このソリューションで使用する方法です。RegisterYahooClientOAuthWebSecurityRegisterClient

このアイデアは、http: //mvc4beginner.com/Sample-Code/Facebook-Twitter/MVC-4-oAuth-Facebook-Login-EMail-Problem-Solved.htmlで提供されているコードから生まれました。

ただし、ソリューションによって提供されるハッキーなアプローチは使用しません。FacebookScopedClient代わりに、 を実装するという名前の新しいクラスを作成しますIAuthenticationClient。次に、以下を使用してクラスを登録します。

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

AuthConfig.cs で

クラスのコードは次のとおりです。

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;
            }
        }

今では

public ActionResult ExternalLoginCallback(string returnUrl)

のメソッドにはAccountControllerresult.ExtraData電子メールが必要です。

編集: この投稿で一部のコードを見逃していました。以下に追加しています。

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;
        }
    }

乾杯!

于 2012-10-29T16:31:11.487 に答える
13

MVC4 インターネット プロジェクトで NuGet パッケージを更新します。

DotNetOpenAuthCore. すべての依存関係を自動的に更新します。

ここで、result.UserName には、名前の代わりに電子メール アドレスが含まれます。

    [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 });
        }
    }

この理由は?

https://github.com/AArnott/dotnetopenid/blob/a9d2443ee1a35f13c528cce35b5096abae7128f4/src/DotNetOpenAuth.AspNet/Clients/OAuth2/FacebookClient.csが最新の NuGet パッケージで更新されました。

修正を含むコミット: https://github.com/AArnott/dotnetopenid/commit/a9d2443ee1a35f13c528cce35b5096abae7128f4

于 2012-12-09T18:21:18.520 に答える
2

私はVarun's answerを使用しましたが、 AppHarborでホストされているアプリで動作するようにするには、小さな変更を加える必要がありました。

AppHarbor は、ロード バランシングを処理するために、URL のポート番号を使用していくつかのファンキーなことを行う必要があります。詳細については、こちらをご覧ください。要するに、AppHarbor でホストしているときに現在のリクエストの AbsoluteUri を取得すると、80 以外のポート番号を持つ uri が返される場合があります。Facebook 認証で問題が発生します。これは、Facebook 認証で問題が発生するためです。これは、アプリの作成時に指定した URL が返されることを Facebook 認証が想定しているためです。

問題は で発生string rawUrl = context.Request.Url.OriginalString;VerifyAuthentication()ます。このコードを使用するとrawUrl、80 以外のポート番号が含まれている可能性があり、Facebook 認証が失敗します。代わりに、その行を

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

GetRawUrl()関数をクラスに追加します。

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;
}

if (SettingsHelper.GetHostingService() == HostingServices.AppHarbor)アプリケーションが AppHarbor で実行されているかどうかを判断するには、独自のロジックに置き換える必要があります。

于 2013-01-28T16:53:18.660 に答える
-1

私はここで同じ問題に直面しました。「scope」パラメーターをFacebookに渡す唯一の方法は、自分のOAuthクライアントをコーディングすることでした。

これを行うには、DotNetOpenAuth.AspNet.Clients.OAuth2Clientの抽象メソッドを拡張して実装する必要があります。

GetServiceLoginUrlメソッドでは、スコープパラメーターをURLに追加できます。したがって、OAuthWebSecurity.VerifyAuthentication()メソッドを呼び出すと、AuthenticationResult.UserNameがユーザーの電子メールを提供します。

例はここにあります。

幸運を。

于 2012-09-27T16:20:29.153 に答える
-2

それは...次のように行うことができます:

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);
于 2013-04-18T20:37:32.157 に答える