【问题标题】:Serious OAuth issue with MVC4MVC4 的严重 OAuth 问题
【发布时间】:2013-09-19 03:54:30
【问题描述】:

我在使用 OAuth 和 Facebook 时遇到问题。我正在使用 MVC4 标准 OAuth 登录。我在本地没有问题,但在服务器上,这被证明是一个问题。

如果我将以下 URL 粘贴到浏览器中,它可以正常工作:

http://localhost:46260/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=FacebookPro&__sid__=1234somesid456  // this is autogenerated

当我将 facebook 中应用的 URL 更改为当前域并粘贴此 URL 时,我会被重定向到登录失败页面:

http://freersvp.mytakeawaysite.com:80/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=Facebook+Pro&__sid__=1234someid456  // note this is autogenerated

注意以上两个url是redirect uri

以下 URL 是所请求的并导致异常:

网址

https://graph.facebook.com/oauth/access_token?client_id=52*********37&redirect_uri=http%3a%2f%2ffreersvp.mytakeawaysite.com%3a80%2fAccount%2fExternalLoginCallback%3fReturnUrl%3d%252FDashboard%26__provider__%3dFacebook%2bPro%26__sid__%3d3c92eb7e84304afc931ef0ea7b62f56a&client_secret=2123***********4256&code=AQAQIJsj-ondldllVYKdpxJaZouqrlg9sjTcfUxyWhAw8MXbD2DvsOSujg2m7E3s3cvNusCI0ZZoJAuGgu_FLkPyjYMQAkTWDVyHTcAoJD-tezyXgn0vhoFzX3FmuRBHYpyJEM-dk0KgF5ugsTHo9yGjBjrcfMDUGu9IxkKQ36k3gMrwocM1_l5t342Q2kIOHdt8pPcyrs--NzgNyZv48vSq7jkZwuQ95xRjUHG5J-ptcgq0l2BlqjzHDDuvIFH23lpMWHzzqdejdj5ejukz7t_Fnhx-mrpVdcRYhP3JeZ2UOTjAyKQmUB3rInooECcjq4c

例外

  {
       "error": {
          "message": "Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request",
          "type": "OAuthException",
          "code": 100
       }
    }

string token 在以下代码中的 GetUserData 函数中返回 null:

我正在使用 FacebookScopedClient:

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 ex)
        {
        }
        return null;
    }

    private IDictionary<string, string> GetUserData(string accessCode, string redirectURI)
    {
        SessionControl ctl = new SessionControl();
        ctl.SaveParam("redirecturi", redirectURI, -3);
        ctl.Dispose();
        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);

        try
        {


        }
        catch { }
        // this dictionary must contains
        Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
        userData.Add("accesstoken", access_token);

        try
        {
            userData.Add("id", userData["id"]);
        }
        catch { }
        return userData;
    }

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

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

    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["email"];

        if(username == null || username == "")
        {
            username = userData["username"];
        }
        //userData.Remove("id");
        userData.Remove("username");

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

【问题讨论】:

  • 为什么异常示例的提供程序查询字符串参数是__provider__=Facebook+Pro 而不是__provider__=FacebookPro,就像在工作示例和ProviderName 属性中一样?
  • 嗨 CR41G14,你能检查我的答案吗,我已经实现了类似的事情并解决了这个问题。我还用如何从 facebook 代码中获取用户的基本信息来更新答案。

标签: c# asp.net-mvc facebook asp.net-mvc-4 oauth


【解决方案1】:

在通过 url 解码器运行导致错误的发布的 url 后,由于某种原因,问题在于您的 url 编码了整个查询字符串,而不仅仅是 url。

您会在该 url 中注意到一堆 %26 个项目,这些项目是 url 编码的 & 这就是引发错误的原因。 Facebook 解析器看到的是 %26 而不是 & 并将其视为一个参数。

发送到页面时,& 分隔 url 查询字符串参数。如果没有完整的代码,我无法告诉您在哪里查看,但在您的代码中的某些位置您完全编码了整个查询字符串并且需要找到那段代码并且只对嵌入的 url 进行编码。

好的,读完之后可以试试这个理论。

我认为您的代码正在从 Facebook 接收这些内容,对 url 进行编码,然后您的系统正在对其进行重新编码。尝试接收任何接收到的内容并首先对其进行 url 解码,对其进行操作,然后根据需要重新编码。

希望对你有帮助

【讨论】:

  • 只是补充一点,如果你有这样的调用 - Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }),返回的 url 会自动编码,这可能是双重编码的原因。但是,我原以为这会导致在本地和服务器上运行时出现问题。
  • 如果人们要对答案投反对票,请发表评论,说明为什么认真。
【解决方案2】:

在 Facebook 应用中关闭沙盒模式试试。

【讨论】:

    【解决方案3】:

    注意到您的 URL 的查询字符串,我从 Stackoverflow 找到了答案。请查看它是否解决了您的问题: https://stackoverflow.com/a/16699058/2005136

    Steve S 作为回应发布:

    “在我们的例子中,我们做了一些不寻常的事情(所以这可能与你的情况无关)。我们的 redirect_uri 是一个 URL,其中另一个 URL 嵌入为编码路径元素。URL-within-a-URL,双重-encoded 传递给 FB 时,已开始导致 Facebook API 服务器出现问题。

    我们通过将嵌套 URL 的编码更改为长十六进制数字而不是 % 编码解决了这个问题,因此所有 Facebook 服务器看到的是一个简单的 redirect_uri,其中包含路径中的一些十六进制,不受正常 URL 编码/解码的影响。"

    【讨论】:

    • 是的,我确实看到了这个,但没有运气!不确定 URL 有什么问题,因为在本地可以正常工作。我的网址似乎已编码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-13
    • 1970-01-01
    • 2014-06-01
    • 2012-05-09
    • 2014-08-18
    相关资源
    最近更新 更多