JWT使用HS512算法生成全局服务token原理

JWT使用HS512算法生成全局服务token原理


前言

最近需要使用C++服务中根据用户名生成全局服务的token,然后在java服务中印证token正确性。因为java服务中使用jwt库生成全局的token, 我就对应找C++中jwt的库, github中有开源库叫jwt-cpp然后我就下载了, 我使用没有找到java中生成token好使用的接口、没有办法我只有看一下jwt生成token的步骤实现一遍

一、jwt生成token原理

HMACSHA512(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
your-512-bit-secret
) secret base64 encoded

jwt由三部分构成

  • 头部(Header)
  • 负载(Payload)即数据
  • 签证(Signature)

1、 jwt的头部承载两部分信息

  • 声明类型, 即jwt
  • 声明加密的算法 (HMAC、SHA256, HS512)

头部json格式

{"typ“: "JWT", "alg":"HS512"}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

2、Payload数据

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

标准中注册的声明 (建议但不强制使用) :

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明 :

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有的声明 :

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
定义一个payload:

{  "sub": "1234567890",  "name": "John Doe",  "admin": true}

然后将其进行base64加密,得到Jwt的第二部分

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

3、signature

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串(头部在前),然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

UQmqAUhUrpDVV2ST7mZKyLTomVfg7sYkEjmdDI5XF8Q

密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和验证,所以需要保护好。

4、 签名的目的

最后一步签名的过程,实际上是对头部以及载荷内容进行签名。一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小(有可能比我成世界首富的概率还小)。所以,我们就把“不一样的输入产生不一样的输出”当做必然事件来看待吧。
所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。
服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道我们用的是哪一种算法呢?别忘了,我们在JWT的头部中已经用alg字段指明了我们的加密算法了。
如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应。

二、 JWT的HS512算法生成token的C++语言实现

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/hmac.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <iostream>
namespace chen {


	namespace jwt {
	

		//java 从最后 删除'='个数  url-unfriendly base64 char u
		int remove_padding( char*  data, size_t len )
		{
			int paddingCount = 0;
			//int encoded_payload_len = strlen(encoded_payload);
			for (int i = len - 1; i > 0; --i)
			{
				if (data[i] == '=')
				{
					++paddingCount;
				}
				else
				{
					break;
				}
			}
			//replace URL-unfriendly Base64 chars to url-friendly ones:
			for (int i = 0; i < len; ++i)
			{
				if (data[i] == '+')
				{
					data[i] = '-';
				}
				else if (data[i] == '/')
				{
					data[i] = '_';
				}
			}

			return len - paddingCount;
		}



		std::string create_token( const std::string& secret_key,  const std::string& payload)
		{
			// 构建头部
			static const char* header = "{\"alg\":\"HS512\"}";
			char buffer[10240] = {0};

			// 计算 Base64 编码后头部的长度
			int header_len = EVP_ENCODE_LENGTH(strlen(header));

			// 计算 Base64 编码后负载的长度
			int payload_len =   payload.length();// = EVP_ENCODE_LENGTH(strlen(payload));

			// 分配内存存储 Base64 编码后的头部和负载
			 
			char  encoded_header[4096] = {0};
			char  encoded_payload[4096] = {0};
			 
			// Base64 编码头部和负载
			EVP_EncodeBlock((unsigned char*)encoded_header , (const unsigned char*)header, strlen(header));
			EVP_EncodeBlock((unsigned char*)encoded_payload , (const unsigned char*)payload.c_str(), payload.length());

 


			// 构建待签名字符串
			int unsigned_data_len = remove_padding( encoded_header , strlen(encoded_header) ) + remove_padding(encoded_payload, strlen(encoded_payload) ) + 2; // 加上两个点号
			 
			snprintf(buffer, unsigned_data_len, "%s.%s", std::string(encoded_header, remove_padding((char*)encoded_header , strlen(encoded_header) )).c_str(), std::string(encoded_payload, remove_padding((char*)encoded_payload ,  strlen(encoded_payload))).c_str());
			 
			// 使用 HMAC SHA-512 对待签名字符串进行签名
			signed char hmac_result[EVP_MAX_MD_SIZE];// = { 0 };
			unsigned int hmac_len;// = 0;

			HMAC(EVP_sha512(), secret_key.c_str(), secret_key.length(), (const unsigned char*)buffer, strlen(buffer), (unsigned char*)hmac_result, &hmac_len);

			// Base64 编码签名结果
			int signature_len = EVP_ENCODE_LENGTH(hmac_len);
			char encoded_signature[4096 * 2] = {0}; 
			EVP_EncodeBlock((unsigned char*)encoded_signature , (unsigned char*)hmac_result, hmac_len);

			// 构建 JWT token
			int token_len = unsigned_data_len + remove_padding((char *)encoded_signature , strlen(encoded_signature) ) + 1; // 加上两个点号和结尾的 null 字符
			 
			 snprintf(buffer, token_len, "%s.%s.%s", std::string(encoded_header, remove_padding((char*)encoded_header, strlen(encoded_header))).c_str(), std::string(encoded_payload, remove_padding((char*)encoded_payload, strlen(encoded_payload))).c_str(), std::string(encoded_signature, remove_padding((char*)encoded_signature, strlen(encoded_signature))).c_str());

			 
		
			return buffer;
		}
		void test_create_token()
		{
			std::string key = "chensong";
			std::string payload = "{\"chensong\":\"{\\\"userId\\\":18}\",\"sub\":\"chensong\"}";
			std::string token = create_token(key, payload);
			std::cout << "jwt token = " << token << std::endl;
		}
	}
}

总结

JWT的HS512算法实现源码地址:

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用jwt生成token的方法如下: 1. 导入jwt库:首先,需要导入jwt库以便使用其中的相关方法。 2. 定义payload:根据需要,在生成token之前定义一个payload,即包含token中的一些信息,例如用户ID、过期时间等。 3. 设置密钥:生成token使用的密钥是保证token的安全性的关键。你需要设置一个密钥,可以是一个随机字符串。 4. 调用jwt库的generate_token方法:使用jwt库中的generate_token方法,传入payload和密钥,即可生成token。 下面是一个示例代码: ```python import jwt def generate_token(payload, secret_key): token = jwt.encode(payload, secret_key) return token # 示例用法 payload = {'user_id': 1, 'exp': 3600} # 设置用户ID和过期时间(单位:秒) secret_key = 'my_secret_key' # 设置密钥 token = generate_token(payload, secret_key) ``` 在示例代码中,我们定义了一个generate_token函数,它接受payload和密钥作为参数,并使用jwt库中的encode方法生成token。注意,生成token是一个字符串。 请注意,这只是一个简单的示例代码,实际应用中可能需要更多的逻辑来处理用户认证和授权等问题。具体使用jwt生成token的方式可能会因不同的框架或库而略有不同,你可以根据你所使用的具体情况进行适当的调整。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用JWT生成Token,并实现Token刷新API](https://blog.csdn.net/xili2532/article/details/122218117)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值