11

Update2 この投稿は古くなっていますが、まだ関連性があります。以下は、私が解決した方法です。他の人の回答にマークを付けました。質問への回答が良いと思うからです。accountcontrollerで同様のメソッドを呼び出しています(リファクタリングしようとしています:))。文字列はリストでなければなりません...あなたはそれを理解していると思います。

/// <summary>
    /// Use this method when an action fails due to lack of priviligies. It will redirect user to facebook with provided permission request.
    /// Refactor to handle list of request.
    /// </summary>
    /// <param name="permission"></param>
    private static void AddAdditionalPermissions(string permission)
    {
        System.Diagnostics.Trace.TraceInformation(permission + " not authorized for user.");
        string facebook_urlAuthorize_base = "https://graph.facebook.com/oauth/authorize";
        string scope = permission; //see: https://developers.facebook.com/docs/authentication/permissions/ for extended permissions
        string urlAuthorize = facebook_urlAuthorize_base;
        urlAuthorize += "?client_id=" + AppId;
        urlAuthorize += "&redirect_uri=" + "https://fbd.anteckna.nu/";
        urlAuthorize += "&scope=" + scope;

        //redirect the users browser to Facebook to ask the user to authorize our Facebook application
        HttpContext.Current.Response.Redirect(urlAuthorize, true); //this cannot be done using WebRequest since facebook may need to show dialogs in the users browser
    }

次に、facebok C# SDK を使用して /me/home などの facebook を呼び出すすべてのメソッドは、FacebookOAuthException をキャッチし、次のメソッドにリダイレクトします。これは、事前にユーザーに許可を求めるのではなく、必要なときに許可を求めるというベスト プラクティスを適用する方法です。このメソッドには、一致するリダイレクト URL も含まれている必要がありますが、まだ始めたばかりです :)

それが役に立てば幸い!

/// <summary>
    /// Check for what permissions to request or different ways to handle FacebookOAuthExceptions.
    /// </summary>
    /// <param name="foae">The exception object</param>
    public static void HandleAuthorizationsExceptions(FacebookOAuthException foae)
    {
        if (foae.Message.Contains("publish_permissions"))
        {
            AddAdditionalPermissions("publish_permissions");
        }
        else if (foae.Message.Contains("read_stream"))
        {
            AddAdditionalPermissions("read_stream");
        }
        else
        {
            System.Diagnostics.Trace.TraceError("Unhandled error at:" + foae.StackTrace);
        }
    }

更新: この動作は、封印されたクラスでハードコードされたスコープを持つ .Net oauth 実装によって引き起こされます。図 4 を追加して、"email" (.net oauth プロバイダーによってすべての要求と共に送信される) 以外の追加のスコープがない要求パラメーターを示します。「、publish_stream」をクエリ文字列に追加すると、必要な動作が得られます。誰でもこれを達成する方法を知っていますか?

Facebook のベスト プラクティスや代替ソリューションに関する回答やコメントは送信しないでください。別の解決策がありますが、これをデフォルトの registerfacebookclient パラメータで動作させたいと考えています。求めている権限を指定する2つの回答に従って、publish_streamのみを使用するようにアプリケーションを更新しました。

図4クエリ文字列のスコープ パラメーターを示す画像

元の質問: 私はアプリケーション (C#.Net4.5 MVC4、カミソリ ビュー) をセットアップしています。このアプリケーションは、Facebook から利用可能なほとんどすべてのユーザー権限を必要とします。以下のコード例は、私がどのようにセットアップしたかを示しています。

問題は、図 1 で [OK] をクリックすると、Facebook からアプリケーションに送り返されることです。私が理解しているように、「より重い」権限を求める追加の画面(図2)があるはずです。今のところ、図1に記載されている権限のみを取得しています。その部分は機能します...

図1 Facebook 権限ダイアログ C#

図 2 ここに画像の説明を入力

したがって、基本的な AuthConfig.cs を使用して

var facebooksocialData = new Dictionary<string, object>();
            facebooksocialData.Add("scope", "email,publish_stream,read_stream,publish_actions,manage_pages,create_event,offline_access");
            OAuthWebSecurity.RegisterFacebookClient(
                appId: "165359673639901",
                appSecret: "15091cb2094a1996ae6c7b324f0300e6",
                displayName: "Facebook",
                extraData: facebooksocialData);

これは私が応答を処理する方法ですが、ここで Facebook はユーザーに拡張アクセス許可を要求せず、電子メールのみを要求しました。

AccountController.cs

 //
        // GET: /Account/ExternalLoginCallback

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

            // Save the accesstoken into session
            Session["accesstoken"] = result.ExtraData["accesstoken"];
            Session["id"] = result.ExtraData["id"];

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

私が見つけた答えに最も近いのは、同じ問題を抱えていた wp プラグインでした。彼らの問題は、ドメインを localhost に設定することで解決されました。これが私のアプリケーションのセットアップ方法です。

4

3 に答える 3

7

私は同じ問題を抱えています。あなたがしたように、RegisterFacebookClient をディクショナリで構成してアプリのスコープを定義しましたが、残念ながら、構成したとおりに要求にスコープが含まれていませんでした。だから私はそれを見つけまし。うまくいくように見えますが、十分ではありませんでした。だから私はこれを見つけまし

だからここに私の問題を解決するものがあります:

まず、この新しいクライアントをコードに追加しました。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using DotNetOpenAuth.AspNet;
using Newtonsoft.Json;

namespace MyApp.UI.Infrastructure
{
    public class FacebookScopedClient : IAuthenticationClient
    {
        private string appId;
        private string appSecret;
        private string scope;

        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 access_token = token.Substring(token.IndexOf("access_token="), token.IndexOf("&"));
            string data = GetHTML(graphApiMe + "fields=id,name,email,username,gender,link&" + access_token);

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

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

        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=" + scope;
            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["username"];
            userData.Remove("id");
            userData.Remove("username");

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

次のように、新しい Facebook クライアントを使用するために、古い構成を変更します。

古いコード:

OAuthWebSecurity.RegisterFacebookClient(
appId: "<app-id>",
appSecret: "<app-secret>",
displayName: "Facebook",
extraData: facebookExtraData);

新しいコード:

OAuthWebSecurity.RegisterClient(
                    new FacebookScopedClient(
                        "<app-id>",
                        "<app-secret>",
                        "scope"), 
                    "Facebook", 
                    null);

それでおしまい。私を助けたように、それはあなたを助けるかもしれません。

于 2013-09-19T20:55:09.193 に答える
1

まず第一に、offline_accessもう存在しないので、あなたが求めているパーミッションからです。

「[アプリ] Facebook から利用可能なほとんどすべてのユーザー権限が必要です」

Facebook は、後で必要になる可能性があるため、「念のため」最初から大量のパーミッションを要求することを積極的に思いとどまらせています。ユーザーが初めてトリガーしたアクションに実際に必要な場合にのみ、拡張アクセス許可を要求する必要があります。

また、「読み取り」権限と「書き込み」権限を別々に要求することになっています。

これらの側面が実際にエラーを引き起こしているかどうかはわかりませんが、Facebook が読み取り/書き込みに関する開発者アラートをすでに送信していることは知っています。FB の従業員は、これらのアラートは今のところ無視できることを確認しましたが、将来のある時点でこれを強制し始める可能性があります。

于 2013-05-24T08:29:26.803 に答える
1

アプリはこれらのスコープに登録されていますか? 私は Google OAuth に精通しており、1 つのアクセス許可にマップされる別のスコープを持っています。2 番目のウィンドウを取得するには、アプリをスコープに登録する必要があります。それ以外の場合は、最初のポップアップが要求する公開情報にのみアクセスできます..

于 2013-05-24T02:21:06.717 に答える