<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>鉴权 on LeafCxy's Blog</title><link>https://leafcxy.github.io/tags/%E9%89%B4%E6%9D%83/</link><description>Recent content in 鉴权 on LeafCxy's Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Mon, 28 Jul 2025 00:27:29 +0000</lastBuildDate><atom:link href="https://leafcxy.github.io/tags/%E9%89%B4%E6%9D%83/index.xml" rel="self" type="application/rss+xml"/><item><title>JWT</title><link>https://leafcxy.github.io/posts/2025-07-28-2/</link><pubDate>Mon, 28 Jul 2025 00:27:29 +0000</pubDate><guid>https://leafcxy.github.io/posts/2025-07-28-2/</guid><description>&lt;p&gt;JWT（JSON Web Token）是一种开放标准（RFC 7519），用于在各方之间安全地传输信息。以下是关于JWT的关键信息：&lt;/p&gt;
&lt;h2 id="jwt基本概念"&gt;JWT基本概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：JWT是一种基于JSON的开放标准，用于在各方之间安全地传输声明&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：常用于身份验证和信息交换&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构&lt;/strong&gt;：由三部分组成，用点（.）分隔&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="jwt的三个组成部分"&gt;JWT的三个组成部分&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Header（头部）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包含令牌类型和签名算法信息&lt;/li&gt;
&lt;li&gt;例如：&lt;code&gt;{&amp;quot;alg&amp;quot;: &amp;quot;HS256&amp;quot;, &amp;quot;typ&amp;quot;: &amp;quot;JWT&amp;quot;}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Payload（载荷）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包含实际要传输的数据（声明）&lt;/li&gt;
&lt;li&gt;可以包含标准声明（如iss、exp、sub等）或自定义声明&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Signature（签名）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用于验证令牌的完整性&lt;/li&gt;
&lt;li&gt;通过签名算法对前两部分进行签名生成&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="主要特点"&gt;主要特点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;无状态&lt;/strong&gt;：服务端不需要存储会话信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨域支持&lt;/strong&gt;：可以在不同域之间传递&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;紧凑性&lt;/strong&gt;：体积小，适合在URL、POST参数或HTTP头中传输&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自包含&lt;/strong&gt;：载荷中包含用户所需的所有信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见用途"&gt;常见用途&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;身份验证令牌&lt;/li&gt;
&lt;li&gt;单点登录（SSO）&lt;/li&gt;
&lt;li&gt;API认证&lt;/li&gt;
&lt;li&gt;信息交换&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JWT广泛应用于现代Web应用和API安全认证中。&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="起源"&gt;起源&lt;/h2&gt;
&lt;p&gt;需要了解一门技术，首先从为什么产生开始说起是最好的。JWT主要用于用户登录鉴权，所以我们从最传统的session认证开始说起。&lt;/p&gt;
&lt;h2 id="session认证"&gt;session认证&lt;/h2&gt;
&lt;p&gt;众所周知，http协议本身是无状态的协议，那就意味着当有用户向系统使用账户名称和密码进行用户认证之后，下一次请求还要再一次用户认证才行。因为我们不能通过http协议知道是哪个用户发出的请求，所以如果要知道是哪个用户发出的请求，那就需要在服务器保存一份用户信息(保存至session)，然后在认证成功后返回cookie值传递给浏览器，那么用户在下一次请求时就可以带上cookie值，服务器就可以识别是哪个用户发送的请求，是否已认证，是否登录过期等等。这就是传统的session认证方式。session认证的缺点其实很明显，由于session是保存在服务器里，所以如果分布式部署应用的话，会出现session不能共享的问题，很难扩展。于是乎为了解决session共享的问题，又引入了redis，接着往下看。&lt;/p&gt;
&lt;h2 id="token认证"&gt;token认证&lt;/h2&gt;
&lt;p&gt;这种方式跟session的方式流程差不多，不同的地方在于保存的是一个token值到redis，token一般是一串随机的字符(比如UUID)，value一般是用户ID，并且设置一个过期时间。每次请求服务的时候带上token在请求头，后端接收到token则根据token查一下redis是否存在，如果存在则表示用户已认证，如果token不存在则跳到登录界面让用户重新登录，登录成功后返回一个token值给客户端。优点是多台服务器都是使用redis来存取token，不存在不共享的问题，所以容易扩展。缺点是每次请求都需要查一下redis，会造成redis的压力，还有增加了请求的耗时，每个已登录的用户都要保存一个token在redis，也会消耗redis的存储空间。有没有更好的方式呢？接着往下看。&lt;/p&gt;
&lt;h2 id="什么是jwt"&gt;什么是JWT&lt;/h2&gt;
&lt;p&gt;JWT(全称：Json Web Token)是一个开放标准(RFC 7519)，它定义了一种紧凑的、自包含的方式，用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任，因为它是数字签名的。上面说法比较文绉绉，简单点说就是一种认证机制，让后台知道该请求是来自于受信的客户端。&lt;/p&gt;
&lt;p&gt;流程描述一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户使用账号、密码登录应用，登录的请求发送到Authentication Server。
Authentication Server进行用户验证，然后创建JWT字符串返回给客户端。&lt;/li&gt;
&lt;li&gt;客户端请求接口时，在请求头带上JWT。&lt;/li&gt;
&lt;li&gt;Application Server验证JWT合法性，如果合法则继续调用应用接口返回结果。可以看出与token方式有一些不同的地方，就是不需要依赖redis，用户信息存储在客户端。所以关键在于生成JWT，和解析JWT这两个地方。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="jwt的数据结构"&gt;JWT的数据结构&lt;/h2&gt;
&lt;p&gt;JWT一般是这样一个字符串，分为三个部分，以&amp;quot;.&amp;ldquo;隔开：&lt;code&gt;xxxxx.yyyyy.zzzzz&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="header"&gt;Header&lt;/h2&gt;
&lt;p&gt;JWT第一部分是头部分，它是一个描述JWT元数据的Json对象，通常如下所示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;alg&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;HS256&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;typ&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;JWT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;alg属性表示签名使用的算法，默认为HMAC SHA256（写为HS256），typ属性表示令牌的类型，JWT令牌统一写为JWT。
最后，使用Base64 URL算法将上述JSON对象转换为字符串保存。&lt;/p&gt;
&lt;h2 id="payload"&gt;Payload&lt;/h2&gt;
&lt;p&gt;JWT第二部分是Payload，也是一个Json对象，除了包含需要传递的数据，还有七个默认的字段供选择。
分别是，iss：发行人、exp：到期时间、sub：主题、aud：用户、nbf：在此之前不可用、iat：发布时间、jti：JWT ID用于标识该JWT。
如果自定义字段，可以这样定义：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//默认字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;sub&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;主题123&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//自定义字段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;java技术爱好者&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;isAdmin&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;loginTime&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;2021-12-05 12:00:03&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意的是，默认情况下JWT是未加密的，任何人都可以解读其内容，因此如果一些敏感信息不要存放在此，以防信息泄露。
JSON对象也使用Base64 URL算法转换为字符串保存。&lt;/p&gt;
&lt;h2 id="signature"&gt;Signature&lt;/h2&gt;
&lt;p&gt;JWT第三部分是签名。是这样生成的，首先需要指定一个secret，该secret仅仅保存在服务器中，保证不能让其他用户知道。
然后使用Header指定的算法对Header和Payload进行计算，然后就得出一个签名哈希。也就是Signature。
那么Application Server如何进行验证呢？可以利用JWT前两段，用同一套哈希算法和同一个secret计算一个签名值，然后把计算出来的签名值和收到的JWT第三段比较，如果相同则认证通过。&lt;/p&gt;
&lt;h2 id="jwt的优点"&gt;JWT的优点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;json格式的通用性，所以JWT可以跨语言支持，比如Java、JavaScript、PHP、Node等等。&lt;/li&gt;
&lt;li&gt;可以利用Payload存储一些非敏感的信息。&lt;/li&gt;
&lt;li&gt;便于传输，JWT结构简单，字节占用小。&lt;/li&gt;
&lt;li&gt;不需要在服务端保存会话信息，易于应用的扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;最后讲讲JWT的缺点，任何技术都不是完美的，所以我们得用辩证思维去看待任何一项技术。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安全性没法保证，所以jwt里不能存储敏感数据。因为jwt的payload并没有加密，只是用Base64编码而已。&lt;/li&gt;
&lt;li&gt;无法中途废弃。因为一旦签发了一个jwt，在到期之前始终都是有效的，如果用户信息发生更新了，只能等旧的jwt过期后重新签发新的jwt。&lt;/li&gt;
&lt;li&gt;续签问题。当签发的jwt保存在客户端，客户端一直在操作页面，按道理应该一直为客户端续长有效时间，否则当jwt有效期到了就会导致用户需要重新登录。那么怎么为jwt续签呢？最简单粗暴就是每次签发新的jwt，但是由于过于暴力，会影响性能。如果要优雅一点，又要引入Redis解决，但是这又把无状态的jwt硬生生变成了有状态的，违背了初衷。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以印证了那句话，没有最好的技术，只有适合的技术。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 好的，以下是一个使用 C# 语言编写的 JWT 示例程序，您可以参考它来编写您自己的 JWT 程序：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Text;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Security.Claims;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Microsoft.IdentityModel.Tokens;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.IdentityModel.Tokens.Jwt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Main(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 定义 JWT 的签名密钥&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; secretKey = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; SymmetricSecurityKey(Encoding.UTF8.GetBytes(&lt;span style="color:#e6db74"&gt;&amp;#34;my_secret_key&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 定义 JWT 的签名算法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; signingCredentials = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 定义 JWT 的负载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; claims = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Claim(JwtRegisteredClaimNames.Sub, &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Claim(JwtRegisteredClaimNames.NameId, &lt;span style="color:#e6db74"&gt;&amp;#34;John Smith&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Claim(JwtRegisteredClaimNames.Email, &lt;span style="color:#e6db74"&gt;&amp;#34;john.smith@example.com&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建 JWT 的描述信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tokenDescriptor = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; SecurityTokenDescriptor
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Subject = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ClaimsIdentity(claims),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Expires = DateTime.UtcNow.AddDays(&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SigningCredentials = signingCredentials
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建 JWT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tokenHandler = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; JwtSecurityTokenHandler();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; token = tokenHandler.CreateToken(tokenDescriptor);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 输出 JWT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Console.WriteLine(tokenHandler.WriteToken(token));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 在上面的示例程序中，我们首先定义了 JWT 的签名密钥和签名算法。然后我们定义了 JWT 的负载，即包含了一些标准声明和自定义声明。接着我们创建了 JWT 的描述信息，并设置了 JWT 的过期时间和签名凭证。最后我们通过 JwtSecurityTokenHandler 类的 CreateToken 方法创建了 JWT，并通过 WriteToken 方法将 JWT 输出到控制台。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 希望这个示例程序能够帮助您编写您自己的 JWT 程序！&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Text;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; System.Security.Cryptography;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; Main(&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. 设置 JWT 的 header 和 payload&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; header = &lt;span style="color:#e6db74"&gt;&amp;#34;{\&amp;#34;alg\&amp;#34;:\&amp;#34;HS256\&amp;#34;,\&amp;#34;typ\&amp;#34;:\&amp;#34;JWT\&amp;#34;}&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; payload = &lt;span style="color:#e6db74"&gt;&amp;#34;{\&amp;#34;sub\&amp;#34;:\&amp;#34;1234567890\&amp;#34;,\&amp;#34;name\&amp;#34;:\&amp;#34;John Doe\&amp;#34;,\&amp;#34;iat\&amp;#34;:1516239022}&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. 对 header 和 payload 进行 base64 编码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; encodedHeader = Base64UrlEncode(Encoding.UTF8.GetBytes(header));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; encodedPayload = Base64UrlEncode(Encoding.UTF8.GetBytes(payload));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. 使用 HMACSHA256 算法生成签名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; key = Encoding.UTF8.GetBytes(&lt;span style="color:#e6db74"&gt;&amp;#34;your-256-bit-secret&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; hmac = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HMACSHA256(key);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(&lt;span style="color:#e6db74"&gt;$&amp;#34;{encodedHeader}.{encodedPayload}&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 4. 对签名进行 base64 编码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; encodedSignature = Base64UrlEncode(signature);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 5. 拼接 JWT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; jwt = &lt;span style="color:#e6db74"&gt;$&amp;#34;{encodedHeader}.{encodedPayload}.{encodedSignature}&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 6. 输出 JWT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Console.WriteLine(jwt);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; Base64UrlEncode(&lt;span style="color:#66d9ef"&gt;byte&lt;/span&gt;[] input)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; output = Convert.ToBase64String(input);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output = output.Replace(&lt;span style="color:#e6db74"&gt;&amp;#34;+&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-&amp;#34;&lt;/span&gt;).Replace(&lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;_&amp;#34;&lt;/span&gt;).Replace(&lt;span style="color:#e6db74"&gt;&amp;#34;=&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; output;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="oauth"&gt;OAuth&lt;/h2&gt;
&lt;p&gt;在学习OAuth时，会有很多疑问OAuth到底是什么，本文介绍OAuth工作机制.&lt;/p&gt;</description></item></channel></rss>