2017-06-02 68 views
0

因此他们突然决定我需要Spotify Search API的授权头。如何使用Poco Net Library在Spotify中交换令牌代码

我的应用程序运行在C++使用Poco网络库,我无法让它工作。

我经历了所有获取我应该交换令牌的“代码”的过程。我假设这段代码是有效的,尽管我只是使用了一个完全不相关的域,然后将它发送到发送给该页面的变量。

https://developer.spotify.com/web-api/authorization-guide/

这是我的代码不工作:

bool getToken() 
{ 
    Poco::URI loginURI("https://accounts.spotify.com"); 
    Poco::Net::HTTPSClientSession loginSession(loginURI.getHost(), loginURI.getPort(), context); 
//  Poco::Net::HTTPBasicCredentials credentials(clientId, clientSecret); 

    std::ostringstream requestOStr; 
    requestOStr << "https://accounts.spotify.com/api/token?grant_type=authorization_code&code=" 
      << (m_refreshToken.empty() ? code : m_refreshToken) 
      << "&redirect_uri=" << redirectURI 
      << "&client_id=" << clientId << "&client_secret=" << clientSecret; 

    std::string requestStr(requestOStr.str()); 
    Poco::Net::HTTPRequest loginRequest(Poco::Net::HTTPRequest::HTTP_POST, requestStr, 
      Poco::Net::HTTPMessage::HTTP_1_1); 

//  credentials.authenticate(loginRequest); 

    loginSession.sendRequest(loginRequest); 
    Poco::Net::HTTPResponse response; 

    std::istream& rs = loginSession.receiveResponse(response); 
    std::cout << "Login request " << requestStr << std::endl; 
    std::cout << "Login response status " << static_cast<int>(response.getStatus()) << ", " 
      << response.getReason() << std::endl; 

    std::string rsStr(std::istreambuf_iterator<char>(rs), {}); 
    if(rsStr.empty()) 
    { 
     std::cout << "No results" << std::endl; 
     return false; 
    } 
    else 
    { 
     std::cout << "Logon response:\n" << rsStr << std::endl; 
    } 
    Parser parser; 
    Var result; 
    result = parser.parse(rsStr); 
    Object::Ptr obj = result.extract<Object::Ptr>(); 
    try 
    { 
     Var tokenVar = obj->get("access_token "); 
     if(tokenVar.isString()) 
     { 
      m_token = tokenVar.convert<std::string>(); 
     } 
     else 
     { 
      std::cerr << "Could not get access token" << std::endl; 
      return false; 
     } 
     Var refreshTokenVar = obj->get("refresh_token"); 
     if(refreshTokenVar.isString()) 
     { 
      m_refreshToken = refreshTokenVar.convert<std::string>(); 
     } 
     return true; 
    } 
    catch(const std::exception& err) 
    { 
     std::cerr << "Error getting login token" << err.what() << std::endl; 
     return false; 
    } 
} 

我试过BasicCredentials而不是把客户端ID和clientSecret到请求但得到了同样的结果。

这是HTTP请求的外观与值修正:

https://accounts.spotify.com/api/token?grant_type=authorization_code&code=THE_CODE&redirect_uri=THE_REDIRECT_URI&client_id=THE_CLIENT_ID&client_secret=THE_CLIENT_SECRET 

我得到的回应是:

Login response status 400, Bad Request 
    {"error":"server_error","error_description":"Unexpected status: 400"} 
+0

那么一个惊喜,我回来一整天后,没有人回答它。无论如何,当我问过以前的问题时,我所看到的都是无稽之谈。 – CashCow

+0

我几乎找到了答案:https://stackoverflow.com/questions/13165877/how-do-i-make-an-http-post-with-http-basic-authentication-using-poco 显然是因为它是一个POST我首先使用body的长度发出请求,我必须设置一对keepAlive标志,然后发送其余的数据。 BasicCredentials也起作用。我只需要知道如何获得授权码,因为我需要这个愚蠢的redirect_uri。 – CashCow

回答

0

好吧,我现在回答我的问题已经找到了答案。我的错误是错误使用POST。

这有效,一旦我有原始authorization_code。一旦“交换”代码将不再有效,但这是一个不同的问题。

bool getToken() 
{ 
    Poco::URI loginURI("https://accounts.spotify.com"); 
    Poco::Net::HTTPSClientSession loginSession(loginURI.getHost(), loginURI.getPort(), context); 
    Poco::Net::HTTPBasicCredentials credentials(clientId, clientSecret); 

    loginSession.setKeepAlive(true); 
    std::string requestStr("https://accounts.spotify.com/api/token"); 
    Poco::Net::HTTPRequest loginRequest(Poco::Net::HTTPRequest::HTTP_POST, 
      requestStr, 
      Poco::Net::HTTPMessage::HTTP_1_1); 
    loginRequest.setContentType("application/x-www-form-urlencoded"); 
    loginRequest.setKeepAlive(true); 

    std::string grantType; 
    std::string authCode; 

    if(m_refreshToken.empty()) 
    { 
     grantType = "authorization_code"; 
     authCode = code; 
    } 
    else 
    { 
     grantType = "refresh_token"; 
     authCode = m_refreshToken; 
    } 
    std::ostringstream contentOStr; 
    contentOStr << "grant_type=" << grantType << 
     "&code=" << authCode 
     << "&redirect_uri=" << redirectURI; 

    std::string contentStr = contentOStr.str(); 
    loginRequest.setContentLength(contentStr.size()); 
    credentials.authenticate(loginRequest); 

    std::ostream& requestOStr = loginSession.sendRequest(loginRequest); 
    requestOStr << contentStr; 
    requestOStr.flush(); 
    Poco::Net::HTTPResponse response; 

    std::istream& rs = loginSession.receiveResponse(response); 
    std::cout << "Login request "; 
    loginRequest.write(std::cout); 
    std::cout << std::endl; 
    std::cout << "Login response status " << static_cast<int>(response.getStatus()) << ", " 
      << response.getReason() << std::endl; 

    std::string rsStr(std::istreambuf_iterator<char>(rs), {}); 
    if(rsStr.empty()) 
    { 
     std::cout << "No results" << std::endl; 
     return false; 
    } 
    else 
    { 
     std::cout << "Logon response:\n" << rsStr << std::endl; 
    } 
    Parser parser; 
    Var result; 
    result = parser.parse(rsStr); 
    Object::Ptr obj = result.extract<Object::Ptr>(); 
    try 
    { 
     Var tokenVar = obj->get("access_token"); 
     if(tokenVar.isString()) 
     { 
      m_token = tokenVar.convert<std::string>(); 
     } 
     else 
     { 
      std::cerr << "Could not get access token" << std::endl; 
      return false; 
     } 
     Var refreshTokenVar = obj->get("refresh_token"); 
     if(refreshTokenVar.isString()) 
     { 
      m_refreshToken = refreshTokenVar.convert<std::string>(); 
     } 
     return true; 
    } 
    catch(const std::exception& err) 
    { 
     std::cerr << "Error getting login token" << err.what() << std::endl; 
     return false; 
    } 
}