1. はじめに
JWT(JSON Web Token)は、JSON 形式で情報をやり取りするための仕様です。
JWT は、ヘッダ、ペイロード、署名の 3 つの部分から構成されています。
ヘッダは、アルゴリズムやトークンの種類を示します。
ペイロードは、トークンに含める情報を示します。
署名は、ヘッダとペイロードを結合して暗号化したものです。
JWT を C++ で扱うためには、以下のライブラリが利用できます。
JWT C++ の中で、以下のライブラリを使用します
Thalhammer/jwt-cpp
選んだ理由としては、Visual Studio 2022 の NuGet でインストールできるからです。
2. NuGet で Thalhammer/jwt-cpp をインストールする
Visual Studio 2022 で、NuGet パッケージマネージャーを開きます。
ツールバーの「プロジェクト」→「NuGet パッケージの管理」を選択します。
参照より「jwt-cpp」を検索し、インストールします。
packages フォルダが作成され、依存関係のライブラリもまとめてインストールされます。
3. サンプルコード実装
Thalhammer/jwt-cpp の Getting Started にあるサンプルコードをコピペします。
#include <jwt-cpp/jwt.h>
#include <iostream>
#include <jwt-cpp/jwt.h>
#include <iostream>
int main() {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCIsInNhbXBsZSI6InRlc3QifQ.lQm3N2bVlqt2-1L-FsOjtR6uE-L4E9zJutMWKIe1v1M";
auto decoded = jwt::decode(token);
for(auto& e : decoded.get_payload_json())
std::cout << e.first << " = " << e.second << std::endl;
}
ビルドして実行すると、以下のように出力されます。
iss = "auth0"
sample = "test"
インストールした NuGet パッケージはソリューションとして管理されるためディレクトリの追加などは不要です。便利ですね。
4. サンプルコード実装2
引き続き、Getting Started にあるサンプルコードをコピペします。
auto verifier = jwt::verify()
.with_issuer("auth0")
.with_claim("sample", jwt::claim(std::string("test")))
.allow_algorithm(jwt::algorithm::hs256{ "secret" });
verifier.verify(decoded);
こちらは、hs256 で暗号化されたトークンを検証するコードです。
NuGet で openssl-vc141-static-x86_64 がインストールされていますが、バージョンが古いためこちらアンインストールします。
かわりに OpenSSL の最新版をソースからビルドしインストールします。← これは、別途記事にします。
トークンの検証に成功すると、エラーが発生せずにプログラムが終了します。
エラーが発生した場合は、例外がスローされるので、try-catch で囲む必要があります。
#include <jwt-cpp/jwt.h>
#include <openssl/ssl.h>
#include <iostream>
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
int main() {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCIsInNhbXBsZSI6InRlc3QifQ.lQm3N2bVlqt2-1L-FsOjtR6uE-L4E9zJutMWKIe1v1M";
std::string token1 = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCIsInNhbXBsZSI6InRlc3QifQ.lQm3N2bVlqt2-1L-FsOjtR6uE-L4E9zJutMWKIe1v2M";
auto decoded = jwt::decode(token);
for (auto& e : decoded.get_payload_json())
std::cout << e.first << " = " << e.second << std::endl;
auto verifier = jwt::verify()
.with_issuer("auth0")
.with_claim("sample", jwt::claim(std::string("test")))
.allow_algorithm(jwt::algorithm::hs256{ "secret" });
try {
verifier.verify(jwt::decode(token));
std::cout << "verify OK" << std::endl;
verifier.verify(jwt::decode(token1));
std::cout << "verify OK" << std::endl;
}
catch (const std::exception& e) {
std::cout << "verify NG " << e.what() << std::endl;
}
}
std::string token1 は、エラーを発生させるために、ペイロードの後ろ2文字目を変更しています。(1 → 2)
以下が出力されます。
iss = "auth0"
sample = "test"
verify OK
verify NG invalid signature
一つ目が成功し、二つ目が失敗しています。意図した動作ですね。
5. サンプルコード実装3
最後に自分でトークンを生成してみます。
#include <jwt-cpp/jwt.h>
#include <openssl/ssl.h>
#include <iostream>
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
int main() {
std::string token = jwt::create()
.set_type("JWT")
.set_issuer("auth0")
.set_payload_claim("sample", jwt::claim(std::string("test")))
.sign(jwt::algorithm::hs256{ "secret" });
std::cout << token << std::endl;
auto decoded = jwt::decode(token);
for (auto& e : decoded.get_payload_json())
std::cout << e.first << " = " << e.second << std::endl;
}
トークンを生成すると、以下のように出力されます。
token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCIsInNhbXBsZSI6InRlc3QifQ.lQm3N2bVlqt2-1L-FsOjtR6uE-L4E9zJutMWKIe1v1M
iss = "auth0"
sample = "test"
set_type("JWS") としているため、3. サンプルコード実装 のトークンと同じになります。
6. まとめ
JWT を C++ で扱うためのライブラリとして、Thalhammer/jwt-cpp を使用しました。
アルゴリズムやペイロードの情報を設定して、トークンを生成することができました。
また、生成したトークンを検証することもできました。
面倒な暗号化処理をライブラリが提供してくれるため、簡単に JWT を扱うことができます。
参考になれば幸いです。
A. 参考サイト
基本から理解するJWTとJWT認証の仕組み
JWT C++
Thalhammer/jwt-cpp
C++プロジェクトでNuGetを使ってみようよ!(Vol. 1:パッケージ導入編)
コメント