Table of Contents
1 🐮jwt介绍
官网:https://jwt.io/
本文以python来进行实战演示
1.1 什么是jwt
JSON Web Token (JWT) 是一个开放标准 ( RFC 7519 ),它定义了一种紧凑且自包含的方式,用于以json的方式安全传输信息,并且通过数字签名来保证信息是信任的。jwt可以使用秘钥(HMAC算法)或RSA或ECDSA的公钥/私钥对其进行签名。
1.2 使用场景
1.2.1 授权
用户在登录后,后续每个请求都将包含JWT,从而判断用户是否登录、是否有权限等操作。这种方式也被称为单点登录,其开销非常小,并且能够在不同的域中轻松使用。
在Web开发中,我们通常会使用cookie或token的方式进行用户身份验证,jwt是属于token方法实现的一种,下面列出token方式的优点:
- 支持跨域访问
- 无状态:token本身就包含了用户信息,无需保存在服务端。
- 适合移动端:如微信小程序、移动设备不支持cookie的客户端。
- 无需考虑CSRF
1.2.2 信息交换
由于可以对JWT进行签名(例如:使用公钥/私钥),因此您可以确定数据发送者是否为本人。另外,由于使用标头和有效负载计算签名,我们可以验证内容是否被篡改。
JWT最常见的场景就是授权认证,一旦用户登录,后续每个请求都讲包含JWT,系统在每次处理用户请求之前,都要先进行JWT安全校验,通过之后再进行处理。
1.3 JWT结构
JWT由3部分内容构成,并且以( .
)作为分隔:
格式:标题.有效载荷.签名
/``
1.3.1 header
{
'alg':'HS256',
'typ':'JWT'
}
alg
:代表要使用的算法
typ
:代表token类别,这里为 大写 JWT
此部分数据使用转为json并 base64 进行加密。
1.3.2 payload
1、共有声明(按需项,用户自定义添加)
{
'exp':xxx, # Expiration Time 此token的过期时间的时间戳
'iss':xxx,# (Issuer) Claim 指明此token的签发者
'iat':xxx, # (Issued At) Claim 指明此创建时间的时间戳
'aud':xxx, # (Audience) Claim 指明此token签发面向群体
}
2、私有声明(用户自定义key、value)
{
'username':'charles'
}
转为json并用base64加密
1.3.3 signature 签名
这里要采用header中的算法进行,这里使用HS256算法
HS256(自定义key, base64(header), base64(payload))
2 🐮Python 实现
2.1 手动编码
"""
jwt生成
"""
import json
import time
from common.util_encryption import hash_tool
class Util_jwt:
def __init__(self, header, payload, secret):
self.header = header
self.payload = payload
self.secret = secret
async def jwt_sign(self):
bs_header = await hash_tool().get_base64(self.header)
bs_payload = await hash_tool().get_base64(self.payload)
s_group = bs_header + b'.' + bs_payload
return hash_tool().get_sha256(self.secret, s_group)
async def get_jwt_token(self):
jwt_res = await hash_tool().get_base64(self.header) + b'.' + await hash_tool().get_base64(
self.payload) + b'.' + await hash_tool().get_base64(await self.jwt_sign())
return jwt_res
jwt_header = json.dumps({'alg': 'HS256', 'typ': 'JWT'})
jwt_payload = json.dumps({'exp': time.time() + 7200,
'iss': 'couragesteak',
'iat': time.time(),
'data': {
'username': 'charles'
}
})
secret = b"123456"
import asyncio
async def func():
print("========jwt结果 异步==========")
j = Util_jwt(header=jwt_header, payload=jwt_payload, secret=secret)
print(await j.get_jwt_token())
asyncio.run(func())
2.2 jwt包
pip install pyjwt
加密
class hash_tool:
async def get_base64(self, data):
"""
data: str(字符串)
"""
return base64.b64encode(data.encode())
async def get_sha256(self, secret, str):
"""
key: 秘钥串
str: 原文
"""
hash = hashlib.sha256(secret)
hash.update(bytes(str))
return hash.hexdigest()
异步实现
"""
jwt生成
"""
import json
import time
from common.util_encryption import hash_tool
class Util_jwt:
def __init__(self, header, payload, secret):
self.header = header
self.payload = payload
self.secret = secret
async def jwt_sign(self):
bs_header = await hash_tool().get_base64(self.header)
bs_payload = await hash_tool().get_base64(self.payload)
s_group = bs_header + b'.' + bs_payload
return hash_tool().get_sha256(self.secret, s_group)
async def get_jwt_token(self):
jwt_res = await hash_tool().get_base64(self.header) + b'.' + await hash_tool().get_base64(
self.payload) + b'.' + await hash_tool().get_base64(await self.jwt_sign())
return jwt_res
secret = b"123456"
jwt_header = json.dumps({'alg': 'HS256', 'typ': 'JWT'})
jwt_payload = json.dumps({'exp': time.time() + 7200,
'iss': 'couragesteak',
'iat': time.time(),
'data': {
'username': 'charles'
}
})
import asyncio
async def func():
print("========jwt结果 异步==========")
j = Util_jwt(header=jwt_header, payload=jwt_payload, secret=secret)
print(await j.get_jwt_token())
asyncio.run(func())
3 🐮校验 jwt
官网校验:https://jwt.io/

4 🐮js解析jwt
<script src="https://cdn.jsdelivr.net/npm/js-base64@3.7.2/base64.min.js"></script>
function jwt_parse(token) {
return Base64.atob(token.split(".")[1]);
}
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJcdTY3MDlcdTUyYzdcdTZjMTRcdTc2ODRcdTcyNWJcdTYzOTIiLCJpYXQiOjE2Njc0NTg5ODAsImV4cCI6MTY2ODA2Mzc4MCwiYXVkIjoid3d3LmNvdXJhZ2VzdGVhay5jb20iLCJkYXRhIjp7InVpZCI6MSwidXNlcm5hbWUiOiJjaGVhcmxlcyJ9fQ.4Xrf3Chpfu1qOnmDy7UQqJAt6dpvKBVxafvr7gdCwdk";
let userinfo = jwt_parse(token)
console.log(userinfo)
结果
{
"iss": "有勇气的牛排",
"iat": 1667458980,
"exp": 1668063780,
"aud": "www.couragesteak.com",
"data": {
"uid": 1,
"username": "charles"
}
}
<p><h3>Table of Contents</h3><ul><ul><li><a href="#1_jwt_3">1 🐮jwt介绍</a></li><ul><li><a href="#11_jwt_6">1.1 什么是jwt</a></li><li><a href="#12__11">1.2 使用场景</a></li><ul><li><a href="#121__12">1.2.1 授权</a></li><li><a href="#122__23">1.2.2 信息交换</a></li></ul><li><a href="#13_JWT_29">1.3 JWT结构</a></li><ul><li><a href="#131_header_34">1.3.1 header</a></li><li><a href="#132_payload_46">1.3.2 payload</a></li><li><a href="#133_signature__66">1.3.3 signature 签名</a></li></ul></ul><li><a href="#2_Python__74">2 🐮Python 实现</a></li><ul><li><a href="#21__75">2.1 手动编码</a></li><li><a href="#22_jwt_124">2.2 jwt包</a></li></ul><li><a href="#3__jwt_205">3 🐮校验 jwt</a></li><li><a href="#4_jsjwt_209">4 🐮js解析jwt</a></li></ul></ul></p>
<h2><a id="1_jwt_3"></a>1 🐮jwt介绍</h2>
<p>官网:<a href="https://jwt.io/" target="_blank">https://jwt.io/</a><br />
本文以python来进行实战演示</p>
<h3><a id="11_jwt_6"></a>1.1 什么是jwt</h3>
<p>JSON Web Token (JWT) 是一个开放标准 ( RFC 7519 ),它定义了一种紧凑且自包含的方式,用于以json的方式安全传输信息,并且通过数字签名来保证信息是信任的。jwt可以使用秘钥(HMAC算法)或RSA或ECDSA的公钥/私钥对其进行签名。</p>
<h3><a id="12__11"></a>1.2 使用场景</h3>
<h4><a id="121__12"></a>1.2.1 授权</h4>
<p>用户在登录后,后续每个请求都将包含JWT,从而判断用户是否登录、是否有权限等操作。这种方式也被称为单点登录,其开销非常小,并且能够在不同的域中轻松使用。</p>
<p>在Web开发中,我们通常会使用cookie或token的方式进行用户身份验证,jwt是属于token方法实现的一种,下面列出token方式的优点:</p>
<ul>
<li>支持跨域访问</li>
<li>无状态:token本身就包含了用户信息,无需保存在服务端。</li>
<li>适合移动端:如微信小程序、移动设备不支持cookie的客户端。</li>
<li>无需考虑CSRF</li>
</ul>
<h4><a id="122__23"></a>1.2.2 信息交换</h4>
<p>由于可以对JWT进行签名(例如:使用公钥/私钥),因此您可以确定数据发送者是否为本人。另外,由于使用标头和有效负载计算签名,我们可以验证内容是否被篡改。</p>
<p>JWT最常见的场景就是授权认证,一旦用户登录,后续每个请求都讲包含JWT,系统在每次处理用户请求之前,都要先进行JWT安全校验,通过之后再进行处理。</p>
<h3><a id="13_JWT_29"></a>1.3 JWT结构</h3>
<p>JWT由3部分内容构成,并且以( <code>.</code> )作为分隔:</p>
<p>格式:<code>标题.有效载荷.签名</code>/``</p>
<h4><a id="131_header_34"></a>1.3.1 header</h4>
<pre><div class="hljs"><code class="lang-json"><span class="hljs-punctuation">{</span>
'alg'<span class="hljs-punctuation">:</span>'HS256'<span class="hljs-punctuation">,</span>
'typ'<span class="hljs-punctuation">:</span>'JWT'
<span class="hljs-punctuation">}</span>
</code></div></pre>
<p><code>alg</code>:代表要使用的算法<br />
<code>typ</code>:代表token类别,这里为 大写 <code>JWT</code></p>
<p>此部分数据使用转为json并 base64 进行加密。</p>
<h4><a id="132_payload_46"></a>1.3.2 payload</h4>
<p>1、共有声明(按需项,用户自定义添加)</p>
<pre><div class="hljs"><code class="lang-json"><span class="hljs-punctuation">{</span>
'exp'<span class="hljs-punctuation">:</span>xxx<span class="hljs-punctuation">,</span> # Expiration Time 此token的过期时间的时间戳
'iss'<span class="hljs-punctuation">:</span>xxx,# (Issuer) Claim 指明此token的签发者
'iat'<span class="hljs-punctuation">:</span>xxx<span class="hljs-punctuation">,</span> # (Issued At) Claim 指明此创建时间的时间戳
'aud'<span class="hljs-punctuation">:</span>xxx<span class="hljs-punctuation">,</span> # (Audience) Claim 指明此token签发面向群体
<span class="hljs-punctuation">}</span>
</code></div></pre>
<p>2、私有声明(用户自定义key、value)</p>
<pre><div class="hljs"><code class="lang-json"><span class="hljs-punctuation">{</span>
'username'<span class="hljs-punctuation">:</span>'charles'
<span class="hljs-punctuation">}</span>
</code></div></pre>
<p>转为json并用base64加密</p>
<h4><a id="133_signature__66"></a>1.3.3 signature 签名</h4>
<p>这里要采用header中的算法进行,这里使用HS256算法</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># 伪代码</span>
HS256(自定义key, base64(header), base64(payload))
</code></div></pre>
<h2><a id="2_Python__74"></a>2 🐮Python 实现</h2>
<h3><a id="21__75"></a>2.1 手动编码</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-string">"""
jwt生成
"""</span>
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">from</span> common.util_encryption <span class="hljs-keyword">import</span> hash_tool
<span class="hljs-keyword">class</span> <span class="hljs-title class_">Util_jwt</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, header, payload, secret</span>):
self.header = header
self.payload = payload
self.secret = secret
<span class="hljs-comment"># 签名</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">jwt_sign</span>(<span class="hljs-params">self</span>):
bs_header = <span class="hljs-keyword">await</span> hash_tool().get_base64(self.header)
bs_payload = <span class="hljs-keyword">await</span> hash_tool().get_base64(self.payload)
s_group = bs_header + <span class="hljs-string">b'.'</span> + bs_payload
<span class="hljs-keyword">return</span> hash_tool().get_sha256(self.secret, s_group)
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_jwt_token</span>(<span class="hljs-params">self</span>):
jwt_res = <span class="hljs-keyword">await</span> hash_tool().get_base64(self.header) + <span class="hljs-string">b'.'</span> + <span class="hljs-keyword">await</span> hash_tool().get_base64(
self.payload) + <span class="hljs-string">b'.'</span> + <span class="hljs-keyword">await</span> hash_tool().get_base64(<span class="hljs-keyword">await</span> self.jwt_sign())
<span class="hljs-keyword">return</span> jwt_res
jwt_header = json.dumps({<span class="hljs-string">'alg'</span>: <span class="hljs-string">'HS256'</span>, <span class="hljs-string">'typ'</span>: <span class="hljs-string">'JWT'</span>})
jwt_payload = json.dumps({<span class="hljs-string">'exp'</span>: time.time() + <span class="hljs-number">7200</span>, <span class="hljs-comment"># Expiration Time 此token的过期时间的时间戳</span>
<span class="hljs-string">'iss'</span>: <span class="hljs-string">'couragesteak'</span>, <span class="hljs-comment"># (Issuer) Claim 指明此token的签发者</span>
<span class="hljs-string">'iat'</span>: time.time(), <span class="hljs-comment"># (Issued At) Claim 指明此创建时间的时间戳</span>
<span class="hljs-string">'data'</span>: {
<span class="hljs-string">'username'</span>: <span class="hljs-string">'charles'</span>
}
})
<span class="hljs-comment"># 私钥</span>
secret = <span class="hljs-string">b"123456"</span>
<span class="hljs-keyword">import</span> asyncio
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>():
<span class="hljs-built_in">print</span>(<span class="hljs-string">"========jwt结果 异步=========="</span>)
j = Util_jwt(header=jwt_header, payload=jwt_payload, secret=secret)
<span class="hljs-built_in">print</span>(<span class="hljs-keyword">await</span> j.get_jwt_token())
asyncio.run(func())
</code></div></pre>
<h3><a id="22_jwt_124"></a>2.2 jwt包</h3>
<pre><div class="hljs"><code class="lang-python">pip install pyjwt
</code></div></pre>
<p>加密</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">hash_tool</span>:
<span class="hljs-comment"># 获取base64加密</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_base64</span>(<span class="hljs-params">self, data</span>):
<span class="hljs-comment"># def get_base64(self, data):</span>
<span class="hljs-string">"""
data: str(字符串)
"""</span>
<span class="hljs-comment"># 封装通用base64加密</span>
<span class="hljs-keyword">return</span> base64.b64encode(data.encode())
<span class="hljs-comment"># 获取sha256加密</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_sha256</span>(<span class="hljs-params">self, secret, <span class="hljs-built_in">str</span></span>):
<span class="hljs-string">"""
key: 秘钥串
str: 原文
"""</span>
<span class="hljs-built_in">hash</span> = hashlib.sha256(secret)
<span class="hljs-built_in">hash</span>.update(<span class="hljs-built_in">bytes</span>(<span class="hljs-built_in">str</span>))
<span class="hljs-keyword">return</span> <span class="hljs-built_in">hash</span>.hexdigest()
</code></div></pre>
<p>异步实现</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-string">"""
jwt生成
"""</span>
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">from</span> common.util_encryption <span class="hljs-keyword">import</span> hash_tool
<span class="hljs-keyword">class</span> <span class="hljs-title class_">Util_jwt</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, header, payload, secret</span>):
self.header = header
self.payload = payload
self.secret = secret
<span class="hljs-comment"># 签名</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">jwt_sign</span>(<span class="hljs-params">self</span>):
bs_header = <span class="hljs-keyword">await</span> hash_tool().get_base64(self.header)
bs_payload = <span class="hljs-keyword">await</span> hash_tool().get_base64(self.payload)
s_group = bs_header + <span class="hljs-string">b'.'</span> + bs_payload
<span class="hljs-keyword">return</span> hash_tool().get_sha256(self.secret, s_group)
<span class="hljs-comment"># 获取token</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_jwt_token</span>(<span class="hljs-params">self</span>):
jwt_res = <span class="hljs-keyword">await</span> hash_tool().get_base64(self.header) + <span class="hljs-string">b'.'</span> + <span class="hljs-keyword">await</span> hash_tool().get_base64(
self.payload) + <span class="hljs-string">b'.'</span> + <span class="hljs-keyword">await</span> hash_tool().get_base64(<span class="hljs-keyword">await</span> self.jwt_sign())
<span class="hljs-keyword">return</span> jwt_res
<span class="hljs-comment"># 私钥</span>
secret = <span class="hljs-string">b"123456"</span>
jwt_header = json.dumps({<span class="hljs-string">'alg'</span>: <span class="hljs-string">'HS256'</span>, <span class="hljs-string">'typ'</span>: <span class="hljs-string">'JWT'</span>})
jwt_payload = json.dumps({<span class="hljs-string">'exp'</span>: time.time() + <span class="hljs-number">7200</span>, <span class="hljs-comment"># Expiration Time 此token的过期时间的时间戳</span>
<span class="hljs-string">'iss'</span>: <span class="hljs-string">'couragesteak'</span>, <span class="hljs-comment"># (Issuer) Claim 指明此token的签发者</span>
<span class="hljs-string">'iat'</span>: time.time(), <span class="hljs-comment"># (Issued At) Claim 指明此创建时间的时间戳</span>
<span class="hljs-string">'data'</span>: {
<span class="hljs-string">'username'</span>: <span class="hljs-string">'charles'</span>
}
})
<span class="hljs-keyword">import</span> asyncio
<span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>():
<span class="hljs-built_in">print</span>(<span class="hljs-string">"========jwt结果 异步=========="</span>)
j = Util_jwt(header=jwt_header, payload=jwt_payload, secret=secret)
<span class="hljs-built_in">print</span>(<span class="hljs-keyword">await</span> j.get_jwt_token())
asyncio.run(func())
</code></div></pre>
<h2><a id="3__jwt_205"></a>3 🐮校验 jwt</h2>
<p>官网校验:<a href="https://jwt.io/" target="_blank">https://jwt.io/</a></p>
<p><img src="https://img-blog.csdnimg.cn/ec8b814aa311499a9276e88b29407dda.png" alt="在这里插入图片描述" /></p>
<h2><a id="4_jsjwt_209"></a>4 🐮js解析jwt</h2>
<pre><div class="hljs"><code class="lang-html"><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/js-base64@3.7.2/base64.min.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
</code></div></pre>
<pre><div class="hljs"><code class="lang-javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">jwt_parse</span>(<span class="hljs-params">token</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-title class_">Base64</span>.<span class="hljs-title function_">atob</span>(token.<span class="hljs-title function_">split</span>(<span class="hljs-string">"."</span>)[<span class="hljs-number">1</span>]);
}
</code></div></pre>
<pre><div class="hljs"><code class="lang-javascript"><span class="hljs-keyword">let</span> token = <span class="hljs-string">"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJcdTY3MDlcdTUyYzdcdTZjMTRcdTc2ODRcdTcyNWJcdTYzOTIiLCJpYXQiOjE2Njc0NTg5ODAsImV4cCI6MTY2ODA2Mzc4MCwiYXVkIjoid3d3LmNvdXJhZ2VzdGVhay5jb20iLCJkYXRhIjp7InVpZCI6MSwidXNlcm5hbWUiOiJjaGVhcmxlcyJ9fQ.4Xrf3Chpfu1qOnmDy7UQqJAt6dpvKBVxafvr7gdCwdk"</span>;
<span class="hljs-keyword">let</span> userinfo = <span class="hljs-title function_">jwt_parse</span>(token)
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(userinfo)
</code></div></pre>
<p>结果</p>
<pre><div class="hljs"><code class="lang-json"><span class="hljs-punctuation">{</span>
<span class="hljs-attr">"iss"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"有勇气的牛排"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"iat"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1667458980</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"exp"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1668063780</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"aud"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"www.couragesteak.com"</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"data"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-attr">"uid"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span>
<span class="hljs-attr">"username"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"charles"</span>
<span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></div></pre>
留言