c++ - 尝试刷新令牌时来自 Spotify Web Api 的 {"error":"invalid_client"}
问题描述
我在 Qt 和 C++ 方面都是新手,但我试图在 uni 项目中使用 spotify web api。不幸的是,我一直坚持将我的刷新令牌发布到 api 以获取新的访问令牌。每次我这样做时,我都会收到响应 {"error":"invalid_client"}。我已经确保我的客户 ID 和客户密码都是正确的。我认为我的标题某处有错误,但我尝试了几件事,但效果不大。
这是我的代码:
void MainWindow::on_pushButton_2_clicked(){
QNetworkAccessManager * manager = new QNetworkAccessManager(this);
QUrl url("https://accounts.spotify.com/api/token");
QNetworkRequest request(url);
QString header = "my_client_id:my_client_secret";
QByteArray ba;
ba.append(header);
ui->teOutput->appendPlainText(ba.toBase64());
QString full_header= "Authorization: Basic " + ba.toBase64();
//ui->teOutput->appendPlainText(full_header);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setHeader(QNetworkRequest::ContentDispositionHeader, full_header);
QUrlQuery params;
params.addQueryItem("grant_type", "refresh_token");
params.addQueryItem("refresh_token", "here_is_my_refresh_token");
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *)));
manager->post(request, params.query().toUtf8());
//ui->teOutput->appendPlainText(params.query().toUtf8());
}
void MainWindow::onFinish(QNetworkReply *rep)
{
QString data = rep->readAll();
ui->teOutput->appendPlainText(data);
}
这就是我的请求的样子(正如我所建议的那样,我已经使用 cUrl 进行了检查)
curl -X "POST" -H "Authorization: Basic xxxxxxxxxxx" -d grant_type=refresh_token -d refresh_token=xxxxxxxxxxxxx https://accounts.spotify.com/api/token
解决方案
该命令-H "Authorization: Basic xxxxxxxxxxx"
等效于:
request.setRawHeader("Authorization", "Basic xxxxxxxxxxx");
所以你应该使用而不是request.setHeader(QNetworkRequest::ContentDispositionHeader, full_header);
.
尽管不需要实现所有逻辑,因为 Spotify API 使用 Qt 在Qt 网络授权模块中实现的 OAuth2。
在请求或刷新令牌时,只应修改 QNetworkRequest 标头,因为这不是 Oauth2 标准的一部分。
常量.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
#include <QByteArray>
#include <QUrl>
namespace Constants {
const QByteArray SPOTIFY_CLIENT_ID = "xxxxxxxx";
const QByteArray SPOTIFY_CLIENT_SECRET = "yyyyyyyy";
const QUrl SPOTIFY_AUTHORIZATION_URL = QUrl("https://accounts.spotify.com/authorize");
const QUrl SPOTIFY_ACCESSTOKEN_URL = QUrl("https://accounts.spotify.com/api/token");
}
#endif // CONSTANTS_H
网络访问管理器.h
#ifndef NETWORKACCESSMANAGER_H
#define NETWORKACCESSMANAGER_H
#include <QNetworkAccessManager>
class NetworkAccessManager : public QNetworkAccessManager
{
public:
using QNetworkAccessManager::QNetworkAccessManager;
protected:
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData);
};
#endif // NETWORKACCESSMANAGER_H
网络访问管理器.cpp
#include "networkaccessmanager.h"
#include "constants.h"
#include <QtGlobal>
QNetworkReply *NetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
const QNetworkRequest &request,
QIODevice *outgoingData)
{
QNetworkRequest r(request);
if(r.url() == Constants::SPOTIFY_ACCESSTOKEN_URL)
r.setRawHeader("Authorization",
"Basic " +
QByteArray(Constants::SPOTIFY_CLIENT_ID + ":" + Constants::SPOTIFY_CLIENT_SECRET).toBase64());
return QNetworkAccessManager::createRequest(op, r, outgoingData);
}
spotifywrapper.h
#ifndef SPOTIFYWRAPPER_H
#define SPOTIFYWRAPPER_H
#include <QOAuth2AuthorizationCodeFlow>
#include <QObject>
class SpotifyWrapper : public QObject
{
Q_OBJECT
public:
explicit SpotifyWrapper(QObject *parent = nullptr);
QNetworkReply *me();
public Q_SLOTS:
void grant();
Q_SIGNALS:
void authenticated();
private:
QOAuth2AuthorizationCodeFlow oauth2;
};
#endif // SPOTIFYWRAPPER_H
spotifywrapper.cpp
#include "spotifywrapper.h"
#include "networkaccessmanager.h"
#include "constants.h"
#include <QDesktopServices>
#include <QOAuthHttpServerReplyHandler>
#include <QUrlQuery>
SpotifyWrapper::SpotifyWrapper(QObject *parent) : QObject(parent)
{
QOAuthHttpServerReplyHandler * replyHandler = new QOAuthHttpServerReplyHandler(1337, this);
replyHandler->setCallbackPath("callback");
oauth2.setNetworkAccessManager(new NetworkAccessManager(this));
oauth2.setReplyHandler(replyHandler);
oauth2.setAuthorizationUrl(Constants::SPOTIFY_AUTHORIZATION_URL);
oauth2.setAccessTokenUrl(Constants::SPOTIFY_ACCESSTOKEN_URL);
oauth2.setClientIdentifier(Constants::SPOTIFY_CLIENT_ID);
oauth2.setScope("user-read-private user-read-email");
oauth2.setState("34fFs29kd09");
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
&QDesktopServices::openUrl);
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::statusChanged, [=](
QAbstractOAuth::Status status) {
if (status == QAbstractOAuth::Status::Granted){
emit authenticated();
}
});
}
void SpotifyWrapper::grant()
{
oauth2.grant();
}
QNetworkReply *SpotifyWrapper::me()
{
return oauth2.get(QUrl("https://api.spotify.com/v1/me"));
}
主文件
#include "spotifywrapper.h"
#include <QNetworkReply>
#include <QGuiApplication>
#include <QTimer>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
SpotifyWrapper wrapper;
wrapper.grant();
QObject::connect(&wrapper, &SpotifyWrapper::authenticated, [&wrapper](){
qDebug() << "authenticated";
QNetworkReply *reply = wrapper.me();
QObject::connect(reply, &QNetworkReply::finished, [=]() {
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError) {
qDebug() << reply->errorString();
return;
}
qDebug() << reply->readAll();
QTimer::singleShot(1000, &QCoreApplication::quit);
});
});
return a.exec();
}
您还必须在应用程序的 SETTINGS 中将重定向 URI 设置为“ http://127.0.0.1:1337/callback ”:
完整的例子可以在这里找到
推荐阅读
- amcharts - AmCharts (V4) 中的样式工具提示
- sonarqube - 如何解决 sonarqube 中的启动错误?
- android - FirebaseApp 在此过程中未初始化 - 此外 FirebaseApp.initializeApp() 不起作用。依赖问题?
- ffmpeg - 如何使用 FFMPEG 连接两个视频(一个没有音频,一个有音频)
- javascript - 单独模块中的模块定义和使用
- mysql - MySQL“等待表元数据锁定”挂在 1 个特定表上
- algorithm - 如何更改合并排序以计算数组与排序数组的距离?
- python - How to define color of specific cell in pandas dataframe based on integer position (e.g., df.iloc[1,1]) with df.style?
- api - 如何解决 500 消息:从 Azure 访问 API 时发生错误?
- java - 如何设置本地浏览器的路径