【问题标题】:MailChimp oauth2 in ASP.NET keeps returning invalid_grantASP.NET 中的 MailChimp oauth2 不断返回 invalid_grant
【发布时间】:2012-09-25 07:56:11
【问题描述】:

我正在开发一个提供与 MailChimp 集成的新应用程序。基本上,它使用户能够轻松地将他们的客户联系信息直接导出到 MailChimp 帐户(即,导出到 MailChimp 内的特定邮件列表)。 所有这些都有效,并且与我的问题有些无关。

为了不要求用户每次都输入 MailChimp-credentials,我即将实现 oauth2 授权工作流程,如下所述:http://apidocs.mailchimp.com/oauth2/

它在第 1-3 步中工作得很好,但是第 4 步让我很生气。 这是我第一次使用 oauth,但我似乎了解了基础知识。

这是我的问题:

当我对 https://login.mailchimp.com/oauth2/token -URI 进行 POST 调用以获取最终访问令牌时,我不断收到 JSON 结果中的错误:"invalid_grant"

我检查了请求和响应流,我的 url 编译正确。

这是我在控制器中的代码:

(GrantEcoAccess 只是授予对另一个应用程序的访问权限 - 其余的应该是不言自明的)

public class HomeController : ApplicationController
{

    private readonly string authorize_uri = "https://login.mailchimp.com/oauth2/authorize";
    private readonly string access_token_uri = "https://login.mailchimp.com/oauth2/token";
    private readonly string mailchimp_clientid2 = "xxx";
    private readonly string mailchimp_secret2 = "yyy";

    ...

    public ActionResult GrantEcoAccess()
    {

        //if exist: use saved token
        var user = (Mailchimp_users)Session["user"];
        if (!string.IsNullOrWhiteSpace(user.EcoToken))
            return RedirectToAction("GrantMailChimpAccess");

        // if !
        var url = "https://secure.e-conomic.com/secure/api1/requestaccess.aspx?role=superuser&appId=MailChimp&redirectUrl=http://localhost:18017/Home/IncomingToken";
        Redirect(url).ExecuteResult(ControllerContext);
        return null;
    }


    public ActionResult IncomingToken(string token)
    {
        var user = (Mailchimp_users)Session["user"];
        user.EcoToken = token;
        EcoSession.DataSession.Refresh(System.Data.Objects.RefreshMode.ClientWins, user);
        EcoSession.DataSession.SaveChanges();

        return RedirectToAction("GrantMailChimpAccess");
    }

    public ActionResult GrantMailChimpAccess()
    {

        //if exist: use saved token
        var user = (Mailchimp_users)Session["user"];
        if (!string.IsNullOrWhiteSpace(user.MailChimpToken))
            return RedirectToAction("Index", "Subscribe");



        //if !
        var url = string.Format("{0}?response_type=code&client_id={1}&redirect_uri=", authorize_uri, mailchimp_clientid2, "http://127.0.0.1:18017/Home/IncomingMailChimpToken");
        Redirect(url).ExecuteResult(ControllerContext);
        return null;
    }

    public ActionResult IncomingMailChimpToken(string code)
    {


        var url = "https://login.mailchimp.com/oauth2/token?grant_type=authorization_code&client_id=XX&client_secret=XX&code=" + code + "&redirect_uri=http://127.0.0.1:18017/Home/AuthComplete";
        //var url = string.Format("?grant_type=authorization_code&client_id={0}&client_secret={1}&code={2}&redirect_uri={3}", mailchimp_clientid, mailchimp_secret, code, Url.Action("AuthComplete"));


        Response.Clear();

        StringBuilder sb = new StringBuilder();
        sb.Append("<html>");
        sb.AppendFormat(@"<body onload='document.forms[""form""].submit()'>");
        sb.AppendFormat("<form name='form' action='{0}' method='post'>", access_token_uri);

        sb.Append("<input type='hidden' name='grant_type' value='authorization_code'>");
        sb.AppendFormat("<input type='hidden' name='client_id' value='{0}'>", mailchimp_clientid2);
        sb.AppendFormat("<input type='hidden' name='client_secret' value='{0}'>", mailchimp_secret2);
        sb.AppendFormat("<input type='hidden' name='code' value='{0}'>", code);
        sb.AppendFormat("<input type='hidden' name='redirect_uri' value='{0}'>", "http://127.0.0.1:18017/Home/AuthComplete");
        // Other params go here

        sb.Append("</form>");
        sb.Append("</body>");
        sb.Append("</html>");

        Response.Write(sb.ToString());
        Response.End();

        return null;

    }

    public ActionResult AuthComplete(string access_token, string expires_in, string scope)
    {
        if (string.IsNullOrWhiteSpace(access_token))
            throw new Exception("Could not authorize user with MailChimp");

        var user = (Mailchimp_users)Session["user"];
        user.MailChimpToken = access_token;
        EcoSession.DataSession.Refresh(System.Data.Objects.RefreshMode.ClientWins, user);
        EcoSession.DataSession.SaveChanges();


        return RedirectToAction("Index", "Subscribe");
    }

}

杀死我的是第 4 步,而不是第 5 步。

【问题讨论】:

  • 我建议您将所有出现的“127.0.0.1”替换为“localhost”。您还应该 urlEncode 查询字符串参数是 url
  • 感谢您的回复。试过了。没有不同。我使用 127.0.0.1 的原因是因为 MailChimp 在他们的应用部分指南中鼓励它。

标签: asp.net asp.net-mvc oauth mailchimp


【解决方案1】:

第 4 步是“您的应用程序必须使用代码向 access_token_uri 发出带外请求”

这里的重点是“带外”。 您必须构建并发送一个发布请求服务器端。 客户端不应该有你的 mailchimp_secret

您的 IncomingMailChimpToken 可能如下所示:

    public ActionResult IncomingMailChimpToken(string code)
    {
        string mcPostData = String.Format(
            "grant_type={0}&client_id={1}&client_secret={2}&code={3}&redirect_url={4}",
            System.Web.HttpUtility.UrlEncode("authorization_code"),
            System.Web.HttpUtility.UrlEncode(mailchimp_clientid2),
            System.Web.HttpUtility.UrlEncode(mailchimp_secret2),
            System.Web.HttpUtility.UrlEncode(code),
            System.Web.HttpUtility.UrlEncode("http://127.0.0.1:18017/Home/AuthComplete")
            );
        WebRequest request = WebRequest.Create(access_token_uri);
        // Set the Method property of the request to POST.
        request.Method = "POST";
        request.ContentType = "application/json";
        byte[] byteArray = Encoding.UTF8.GetBytes(mcPostData);
        request.ContentLength = byteArray.Length;
        // Get the request stream.
        Stream dataStream = request.GetRequestStream();
        // Write the data to the request stream.
        dataStream.Write(byteArray, 0, byteArray.Length);
        // Close the Stream object.
        dataStream.Close();
        // Get the response.
        WebResponse response = request.GetResponse();
        // Get the stream containing content returned by the server.
        dataStream = response.GetResponseStream();
        // Open the stream using a StreamReader for easy access.
        StreamReader reader = new StreamReader(dataStream);
        // Read the content.
        string responseFromServer = reader.ReadToEnd();
        // Cleanup the streams and the response.
        reader.Close ();
        dataStream.Close ();
        response.Close ();

        // parse the json responseFromServer to extract token, expires_in and scope
        // and call AuthComplete with these params
    }

【讨论】:

  • 非常感谢您提供这个解释清楚且评论良好的答案!尽管我自己找到了一个解决方案,它有一个整洁的 oAuth2 .net 包装器,它可以处理所有这些东西。在这里找到它:github.com/jamierytlewski/eepOAuth2-MVC 当然其他人会觉得它很好用。但如果我没有找到这个,我会用这个!现在我终于有了一个关于真正的带外 POST 的解释无论如何你都明白了!
  • @Hulvej:不客气。稍后,我会对您对 mailchimp 集成的简短反馈感兴趣。该产品看起来很棒。
【解决方案2】:

如果您不想自己实现它,有一个不错的包装器,它处理对 MailChimp 的 oAuth2 和 RESTapi 调用。

https://github.com/jamierytlewski/eepOAuth2-MVC

【讨论】:

    【解决方案3】:

    您应该使用 post 在正文中发送您的请求参数,如果您使用 curl php,您会这样做:

    $value = http_build_query($params); //params is an array
    curl_setopt($ch, CURLOPT_POSTFIELDS, $value);
    

    值应如下所示:

    grant_type=authorization_code&client_id=635959587059&client_secret=0da3e7744949e1406b7b250051ee1a95&code=1edf2589e664fd317f6a7ff5f97b42f7&redirect_uri=http%3A%2F%2F192.168.1.8%2Foauth%2Fcomplete.php
    

    请注意,您应该以查询字符串的形式创建正文请求,不要发送 json,他们不会找到您的参数。 如果您在执行此操作后收到无效的授权响应或其他问题,请检查您用于获取第一个代码的重定向 uri 是否与您发送以获取令牌的重定向 uri 完全相同。

    另外,对于那些使用 PHP 的,为了匹配 mailchimp documentation 状态使用这个:

    curl_setopt($ch, CURLOPT_USERAGENT, 'oauth2-draft-v10');
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
    

    【讨论】:

    • 谢谢。我遇到了一个问题,不知道重定向 uri 必须与发送获取令牌的 uri 完全相同
    猜你喜欢
    • 2012-04-19
    • 1970-01-01
    • 2017-01-02
    • 2021-12-03
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    相关资源
    最近更新 更多