C# MVC4存在严重的OAuth问题

C# MVC4存在严重的OAuth问题,c#,asp.net-mvc,facebook,asp.net-mvc-4,oauth,C#,Asp.net Mvc,Facebook,Asp.net Mvc 4,Oauth,我对OAuth和Facebook有意见。我使用的是MVC4标准OAuth登录。我没有本地问题,但在服务器上,这证明是一个问题 如果我将以下URL粘贴到浏览器中,它可以正常工作: http://localhost:46260/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=FacebookPro&__sid__=1234somesid456 // this is autogenerated 当我

我对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
N.B以上两个url是重定向uri

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

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
       }
    }
字符串标记
在下面代码中的
GetUserData
函数中返回空值:

我正在使用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;
    }
}
公共类FacebookScopedClient:IAAuthenticationClient
{
私有字符串appId;
私密字符串;
私有字符串范围;
私有常量字符串baseUrl=”https://www.facebook.com/dialog/oauth?client_id=";
公共常量字符串graphApiToken=”https://graph.facebook.com/oauth/access_token?";
公用常量字符串GraphaTime=”https://graph.facebook.com/me?";
私有静态字符串GetHTML(字符串URL)
{
字符串connectionString=URL;
尝试
{
System.Net.HttpWebRequest myRequest=(HttpWebRequest)WebRequest.Create(connectionString);
myRequest.Credentials=CredentialCache.DefaultCredentials;
////得到回应
WebResponse WebResponse=myRequest.GetResponse();
Stream respStream=webResponse.GetResponseStream();
////
StreamReader ioStream=新StreamReader(respStream);
字符串pageContent=ioStream.ReadToEnd();
////合流
ioStream.Close();
respStream.Close();
返回页面内容;
}
捕获(例外情况除外)
{
}
返回null;
}
私有IDictionary GetUserData(字符串访问代码、字符串重定向URI)
{
SessionControl ctl=新SessionControl();
ctl.SaveParam(“重定向URI”,重定向URI,-3);
ctl.Dispose();
string token=GetHTML(graphApiToken+“client_id=“+appId+”&redirect_uri=“+HttpUtility.UrlEncode(redirectURI)+”&client_secret=“+appSecret+”&code=“+accessCode”);
如果(标记==null | |标记==“”)
{
返回null;
}
string access_token=token.Substring(token.IndexOf(“access_token=”),token.IndexOf(&”);
字符串数据=GetHTML(GraphaTime+“字段=id、姓名、电子邮件、用户名、性别、链接和“+access\u令牌);
尝试
{
}
捕获{}
//这本词典必须包含
Dictionary userData=JsonConvert.DeserializeObject(数据);
添加(“accesstoken”,访问令牌);
尝试
{
userData.Add(“id”,userData[“id]”);
}
捕获{}
返回用户数据;
}
public FacebookScopedClient(字符串appId、字符串appSecret、字符串作用域)
{
this.appId=appId;
this.appSecret=appSecret;
this.scope=范围;
}
公共字符串提供程序名
{
获取{return“FacebookPro”;}
}
public void RequestAuthentication(System.Web.HttpContextBase上下文,Uri returnUrl)
{
字符串url=baseUrl+appId+“&redirect_uri=“+HttpUtility.UrlEncode(returnUrl.ToString())+”&scope=“+scope;
context.Response.Redirect(url);
}
公共身份验证结果验证身份验证(System.Web.HttpContextBase上下文)
{
字符串代码=context.Request.QueryString[“code”];
字符串rawUrl=context.Request.Url.OriginalString;
//我们需要从中删除代码部分
替换(rawUrl,&code=[^&]*,”);
IDictionary userData=GetUserData(代码,rawUrl);
if(userData==null)
返回新的AuthenticationResult(false,ProviderName,null,null,null);
字符串id=userData[“id”];
字符串username=userData[“email”];
如果(用户名==null | |用户名==“”)
{
用户名=用户数据[“用户名”];
}
//userData.Remove(“id”);
userData.Remove(“用户名”);
AuthenticationResult=新的AuthenticationResult(true、ProviderName、id、用户名、userData);
返回结果;
}
}

注意到您的URL的查询字符串,我从Stackoverflow中找到了答案。请查看它是否解决了您的问题:

Steve S作为回应发布:

“在我们的案例中,我们做了一些不寻常的事情(因此这可能与您的案例无关)。我们的redirect_uri是一个URL,另一个URL作为编码路径元素嵌入。URL-In-a-URL在传递给FB时经过双重编码,已开始导致Facebook API服务器出现问题


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

在facebook应用程序中关闭沙箱模式时尝试此操作。

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

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

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

好的,在读过这些东西之后,也许可以试试这个理论

我想你的代码是从Facebook接收这些东西,url编码,然后是你的s