Mat*_*inz 6 c++ openssl jwt json-web-token
我是一个相当新手的c ++程序员(我还在上大学所以我想我一般都是一个相当新手的程序员)而且我正在尝试用c ++生成一个JWT.我能够生成并编码头和有效负载,但是当我在jwt.io上检查时,使用openssl的hmac库生成的签名似乎无效.我有一种感觉,这是由于一些细微差别,我只是没有看到.如果你能找到我的错误,我会非常感激.如果您也有关于如何改进我的代码的建议,也将不胜感激.注意我必须使用openssl和boost for json.
********更新
我发现正在添加额外的新行,这会在身份验证期间导致错误.目前我正在调用str.erase来删除它们,但是如果有人可以让我知道他们来的地方我会很感激所以我可以避免操纵字符串
char* Auth::genJWT()
{
ptree pt;
std::stringstream jwt;
//Make and encode header
pt.put("typ","JWT");
pt.put("alg","HS256");
std::ostringstream buf;
write_json(buf, pt, false);
std::string header = buf.str();
jwt << base64_encode((unsigned char*)header.c_str(), (int) header.length());
//clear buffer
pt.clear();
buf.clear();
buf.str("");
//make pay load
pt.put("org_guid", Config::organization_guid);
pt.put("agent_guid", Config::agent_guid);
write_json(buf, pt, false);
std::string payload = buf.str();
jwt << '.' << base64_encode((unsigned char*)payload.c_str(), (int) payload.length());
//sign data
std::string signed_data = signToken(jwt.str());
jwt << '.' << base64_encode((unsigned char*) signed_data.c_str(), (int) signed_data.length());
//jwt made
std::cout << "JWT Token: " << jwt.str() << std::endl;
//Note I am testing by copying the token into an online debugger
//returning "" is not my bug
return "";
}
Run Code Online (Sandbox Code Playgroud)
这是我使用签名令牌的方法
std::string Auth::signToken(std::string to_sign)
{
//std::string key = Config::secret;
std::string key = "foo";
unsigned int len = 32;
unsigned char signed_data[32];
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, &key[0], (int) key.length(), EVP_sha256(), NULL);
HMAC_Update(&ctx, (unsigned char*)&to_sign[0], to_sign.length());
HMAC_Final(&ctx, signed_data, &len);
HMAC_CTX_cleanup(&ctx);
std::stringstream ss;
ss << std::setfill('0');
for(unsigned int i = 0; i < len; i++)
{
ss << signed_data[i];
}
return (ss.str());
}
Run Code Online (Sandbox Code Playgroud)
这是我在base64Url中编码数据的方式
std::string Auth::base64_encode(const unsigned char* input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
std::stringstream ss;
//make URL safe
for(unsigned int i = 0; i < bptr->length - 1; i++)
{
switch(bptr->data[i])
{
case '+':
ss << '_';
break;
case '/':
ss << '-';
break;
case '=':
//don't add in padding
break;
default:
ss << bptr->data[i];
break;
}
}
BIO_free_all(b64);
return (ss.str());
}
Run Code Online (Sandbox Code Playgroud)
OpenSSL在每个第64个字符后插入一个换行符,你可以使用以下命令禁用它:
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
Run Code Online (Sandbox Code Playgroud)
请参阅此处的文档.
在测试代码时,我还发现了以下两个问题:
1)在使URL安全时跳过缓冲区的最后一个字符.你应该删除-1.
for(unsigned int i = 0; i < bptr->length ; i++)
Run Code Online (Sandbox Code Playgroud)
2)在使Base64输出URL安全时,您需要将'+'替换为' - ',将'/'替换为'_'.你的代码反过来了.所以:
case '+':
ss << '-';
break;
case '/':
ss << '_';
break;
Run Code Online (Sandbox Code Playgroud)