赵换顺 發表於 2022-11-17 10:51:00

SpringBoot学习笔记(八)——JWT、(Vue3、Axios、Vue-Router、TypeScript实现授权与验证示例)

<h1>一、JWT概要</h1>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221116105405639-394444781.png" alt="" loading="lazy"></p>
<h2>1.0、认证方式</h2>
<h3>1.0.1、基于Session的认证</h3>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221116115051923-1067320786.png" alt="" width="901" height="409" loading="lazy"></p>
<p><strong>基于session认证所显露的问题:</strong></p>
<p>&nbsp;<strong>Session:</strong>&nbsp;每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。</p>
<p><strong>扩展性:</strong>&nbsp;用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。</p>
<p><strong>CSRF:</strong>&nbsp;因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。</p>
<h3>1.0.2、基于传统token的认证</h3>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221116115450904-338327268.png" alt="" width="956" height="435" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>传统的Token,例如:用户登录成功生成对应的令牌,key为令牌 value:userid,隐藏了数据真实性 ,同时将该token存放到redis中,返回对应的真实令牌给客户端存放。<br>客户端每次访问后端请求的时候,会传递该token在请求中,服务器端接收到该token之后,从redis中查询如果存在的情况下,则说明在有效期内,如果在Redis中不存在的情况下,则说明过期或者token错误。</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221116115541876-485412103.png" alt="" width="447" height="256" loading="lazy"></p>
<h2>1.1. JWT是什么</h2>
<p>JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。</p>
<p>是目前流行的<span style="color: rgba(255, 0, 0, 1)">跨域认证解决方案</span>,一种基于JSON的、用于在网络上声明某种主张的令牌(token)。</p>
<p>该token被设计为紧凑且安全的,特别适用于<span style="color: rgba(255, 0, 0, 1)">分布式站点的单点登录(SSO)</span>场景。</p>
<p>JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。</p>
<p>原理:jwt验证方式是将用户信息通过加密生成token,每次请求服务端只需要使用保存的密钥验证token的正确性,不用再保存任何session数据了,进而服务端变得无状态,容易实现拓展。</p>
<p>官网:https://jwt.io/</p>
<h2>1.2. 什么时候你应该用JWT</h2>
<p>下列场景中使用JSON Web Token是很有用的:</p>
<ul>
<li><strong>Authorization</strong>&nbsp;(授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。<span style="color: rgba(255, 0, 0, 1)">单点登录</span>是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地<span style="color: rgba(255, 0, 0, 1)">跨域</span>使用。</li>
<li><strong>Information Exchange</strong>&nbsp;(信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。</li>













</ul>
<h2>1.3. JWT的结构是什么样的</h2>
<p><img src="https://images2018.cnblogs.com/blog/874963/201807/874963-20180709124807031-664967381.png" alt="" class="medium-zoom-image"></p>
<p>JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:</p>
<ul>
<li>Header</li>
<li>Payload</li>
<li>Signature</li>













</ul>
<p>因此,一个典型的JWT看起来是这个样子的:</p>
<p>xxxxx.yyyyy.zzzzz</p>
<p>接下来,具体看一下每一部分:</p>
<h3>1.3.1、Header头部</h3>
<p>header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。</p>
<p>例如:</p>
<p><img src="https://images2018.cnblogs.com/blog/874963/201807/874963-20180707143936465-1142974441.png" alt=""></p>
<p>然后,用Base64对这个JSON编码就得到JWT的第一部分</p>
<ul>
<li>typ 为声明类型,指定 "JWT"</li>
<li>alg 为加密的算法,默认是 "HS256"</li>












</ul>
<p>也可以是下列中的算法:</p>
<div class="table-wrapper">
<table>
<thead>
<tr><th>JWS</th><th>算法名称</th><th>描述</th></tr>












</thead>
<tbody>
<tr>
<td>HS256</td>
<td>HMAC256</td>
<td>HMAC with SHA-256</td>












</tr>
<tr>
<td>HS384</td>
<td>HMAC384</td>
<td>HMAC with SHA-384</td>












</tr>
<tr>
<td>HS512</td>
<td>HMAC512</td>
<td>HMAC with SHA-512</td>












</tr>
<tr>
<td>RS256</td>
<td>RSA256</td>
<td>RSASSA-PKCS1-v1_5 with SHA-256</td>












</tr>
<tr>
<td>RS384</td>
<td>RSA384</td>
<td>RSASSA-PKCS1-v1_5 with SHA-384</td>












</tr>
<tr>
<td>RS512</td>
<td>RSA512</td>
<td>RSASSA-PKCS1-v1_5 with SHA-512</td>












</tr>
<tr>
<td>ES256</td>
<td>ECDSA256</td>
<td>ECDSA with curve P-256 and SHA-256</td>












</tr>
<tr>
<td>ES384</td>
<td>ECDSA384</td>
<td>ECDSA with curve P-384 and SHA-384</td>












</tr>
<tr>
<td>ES512</td>
<td>ECDSA512</td>
<td>ECDSA with curve P-521 and SHA-512</td>












</tr>












</tbody>












</table>












</div>
<h3>1.3.2、Payload装载</h3>
<p>JWT的第二部分是payload,它包含声明(要求)。声明是关于实体(通常是用户)和其他数据的声明。声明有三种类型: registered, public 和 private。</p>
<ul>
<li>Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。
<ul>
<li>iss (issuer):签发人</li>
<li>exp (expiration time):过期时间</li>
<li>sub (subject):主题</li>
<li>aud (audience):受众</li>
<li>nbf (Not Before):生效时间</li>
<li>iat (Issued At):签发时间</li>
<li>jti (JWT ID):编号</li>












</ul>












</li>
<li>Public claims : 可以随意定义。</li>
<li>Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。</li>













</ul>
<p>下面是一个例子:</p>
<p><img src="https://images2018.cnblogs.com/blog/874963/201807/874963-20180707144153274-292205768.png" alt=""></p>
<p>对payload进行Base64编码就得到JWT的第二部分</p>
<p>注意,不要在JWT的payload或header中放置敏感信息,除非它们是加密的。</p>
<h3>1.3.3、Signature签名</h3>
<p>为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre>HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)</pre>
</div>
<p>签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。</p>
<p>看一张官网的图就明白了:</p>
<p><img src="https://images2018.cnblogs.com/blog/874963/201807/874963-20180707150229764-2037235703.png" alt="" width="824" height="577" class="medium-zoom-image"></p>
<h2>1.4. JWT是如何工作的</h2>
<p>在认证的时候,当用户用他们的凭证成功登录以后,一个JSON Web Token将会被返回。此后,token就是用户凭证了,你必须非常小心以防止出现安全问题。一般而言,你保存令牌的时候不应该超过你所需要它的时间。</p>
<p>无论何时用户想要访问受保护的路由或者资源的时候,用户代理(通常是浏览器)都应该带上JWT,典型的,通常放在Authorization header中,用Bearer schema。</p>
<p>header应该看起来是这样的:</p>
<p>Authorization: Bearer &lt;token&gt;</p>
<p>服务器上的受保护的路由将会检查Authorization header中的JWT是否有效,如果有效,则用户可以访问受保护的资源。如果JWT包含足够多的必需的数据,那么就可以减少对某些操作的数据库查询的需要,尽管可能并不总是如此。</p>
<p>如果token是在授权头(Authorization header)中发送的,那么跨源资源共享(CORS)将不会成为问题,因为它不使用cookie。</p>
<p>下面这张图显示了如何获取JWT以及使用它来访问APIs或者资源:</p>
<p><img src="https://images2018.cnblogs.com/blog/874963/201807/874963-20180707144719025-1833412608.png" alt="" width="738" height="281" class="medium-zoom-image"></p>
<ol>
<li>应用(或者客户端)想授权服务器请求授权。例如,如果用授权码流程的话,就是/oauth/authorize</li>
<li>当授权被许可以后,授权服务器返回一个access token给应用</li>
<li>应用使用access token访问受保护的资源(比如:API)</li>
</ol>
<h2>1.5.&nbsp;基于Token的身份认证 与 基于服务器的身份认证</h2>
<h3>1.5.1.&nbsp;基于服务器的身份认证</h3>
<p>在讨论基于Token的身份认证是如何工作的以及它的好处之前,我们先来看一下以前我们是怎么做的:</p>
<blockquote>
<p>HTTP协议是无状态的,也就是说,如果我们已经认证了一个用户,那么他下一次请求的时候,服务器不知道我是谁,我们必须再次认证</p>
</blockquote>
<p>传统的做法是将已经认证过的用户信息存储在服务器上,比如Session。用户下次请求的时候带着Session ID,然后服务器以此检查用户是否认证过。</p>
<p>这种基于服务器的身份认证方式存在一些问题:</p>
<ul>
<li>Sessions : 每次用户认证通过以后,服务器需要创建一条记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大。</li>
<li>Scalability : 由于Session是在内存中的,这就带来一些扩展性的问题。</li>
<li>CORS : 当我们想要扩展我们的应用,让我们的数据被多个移动设备使用时,我们必须考虑跨资源共享问题。当使用AJAX调用从另一个域名下获取资源时,我们可能会遇到禁止请求的问题。</li>
<li>CSRF :&nbsp;用户很容易受到CSRF攻击。</li>
</ul>
<h3>1.5.2.&nbsp;JWT与Session的差异</h3>
<p>相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。</p>
<p>Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。</p>
<p>而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。</p>
<p>Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221116141317884-1227463043.png" alt="" width="452" height="526" loading="lazy"></p>
<h3>1.5.3. 基于Token的身份认证是如何工作的</h3>
<p>基于Token的身份认证是无状态的,服务器或者Session中不会存储任何用户信息。</p>
<blockquote>
<p>没有会话信息意味着应用程序可以根据需要扩展和添加更多的机器,而不必担心用户登录的位置。</p>
</blockquote>
<p>虽然这一实现可能会有所不同,但其主要流程如下:</p>
<ol>
<li>用户携带用户名和密码请求访问</li>
<li>服务器校验用户凭据</li>
<li>应用提供一个token给客户端</li>
<li>客户端存储token,并且在随后的每一次请求中都带着它</li>
<li>服务器校验token并返回数据</li>
</ol>
<p>注意:</p>
<ol>
<li>每一次请求都需要token</li>
<li>Token应该放在请求header中</li>
<li>我们还需要将服务器设置为接受来自所有域的请求,用Access-Control-Allow-Origin: *</li>
</ol>
<h3>1.5.4. 用Token的好处</h3>
<ul>
<li>无状态和可扩展性:Tokens存储在客户端。完全无状态,可扩展。我们的负载均衡器可以将用户传递到任意服务器,因为在任何地方都没有状态或会话信息。</li>
<li>安全:Token不是Cookie。(The token, not a cookie.)每次请求的时候Token都会被发送。而且,由于没有Cookie被发送,还有助于防止CSRF攻击。即使在你的实现中将token存储到客户端的Cookie中,这个Cookie也只是一种存储机制,而非身份认证机制。没有基于会话的信息可以操作,因为我们没有会话!</li>
</ul>
<blockquote>
<p><img src="https://images2018.cnblogs.com/blog/874963/201807/874963-20180707162551160-1143708148.png" alt="" class="medium-zoom-image"></p>
</blockquote>
<p>还有一点,token在一段时间以后会过期,这个时候用户需要重新登录。这有助于我们保持安全。还有一个概念叫token撤销,它允许我们根据相同的授权许可使特定的token甚至一组token无效。</p>
<h3>1.5.5. JWT与OAuth的区别</h3>
<ol>
<li>OAuth2是一种授权框架 ,JWT是一种认证协议</li>
<li>无论使用哪种方式切记用HTTPS来保证数据的安全性</li>
<li>OAuth2用在使用第三方账号登录的情况(比如使用weibo, qq, github登录某个app),而<strong>JWT是用在前后端分离</strong>, 需要简单的对后台API进行保护时使用。</li>
</ol>
<h3>1.5.6. 关于OAuth可以参考下面几篇</h3>
<p>《OAuth 2.0》</p>
<p>《Spring Security OAuth 2.0》</p>
<p>《OAuth 2.0 授权码请求》</p>
<h2>1.6. 参考</h2>
<p>https://jwt.io/</p>
<p>https://scotch.io/tutorials/the-ins-and-outs-of-token-based-authentication#toc-why-tokens-came-around</p>
<p>https://tools.ietf.org/html/rfc7519#section-3</p>
<p>http://blog.leapoahead.com/2015/09/06/understanding-jwt/</p>
<p>https://cnodejs.org/topic/557844a8e3cc2f192486a8ff</p>
<p>http://blog.leapoahead.com/2015/09/07/user-authentication-with-jwt/</p>
<h1>二、JJWT实现</h1>
<h2>2.1、概要</h2>
<p data-pid="hPpm-Gjj">JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。</p>
<ul>
<li data-pid="-E1Mrc-A">JJWT的目标是最容易使用和理解用于在JVM上创建和验证JSON Web令牌(JWTs)的库。</li>
<li data-pid="N-xQt96K">JJWT是基于JWT、JWS、JWE、JWK和JWA RFC规范的Java实现。</li>
<li data-pid="SfYDemf-">JJWT还添加了一些不属于规范的便利扩展,比如JWT压缩和索赔强制。</li>
</ul>
<p>源码:https://github.com/jwtk/jjwt</p>
<h2 id="h_432033222_4">2.2、规范兼容</h2>
<ul>
<li data-pid="IIE8M6Ry">创建和解析明文压缩JWTs</li>
<li data-pid="8xRrAjcP">创建、解析和验证所有标准JWS算法的数字签名紧凑JWTs(又称JWSs):</li>
<li data-pid="DMgxRV3f">HS256: HMAC using SHA-256</li>
<li data-pid="zn_xaW3V">HS384: HMAC using SHA-384</li>
<li data-pid="z0C4fftk">HS512: HMAC using SHA-512</li>
<li data-pid="NDwtDGqW">RS256: RSASSA-PKCS-v1_5 using SHA-256</li>
<li data-pid="YhKlfC8p">RS384: RSASSA-PKCS-v1_5 using SHA-384</li>
<li data-pid="gsWFlJV2">RS512: RSASSA-PKCS-v1_5 using SHA-512</li>
<li data-pid="5QMRp6uo">PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256</li>
<li data-pid="11o01MTz">PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384</li>
<li data-pid="jvmL2CAN">PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512</li>
<li data-pid="SOM1mbpd">ES256: ECDSA using P-256 and SHA-256</li>
<li data-pid="Tdo_abf0">ES384: ECDSA using P-384 and SHA-384</li>
<li data-pid="XknkiUQS">ES512: ECDSA using P-521 and SHA-512</li>
</ul>
<h2>2.3、添加依赖</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>io.jsonwebtoken<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>jjwt-api<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>0.11.5<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>io.jsonwebtoken<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>jjwt-impl<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>0.11.5<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>runtime<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>io.jsonwebtoken<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>jjwt-jackson<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span> <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> or jjwt-gson if Gson is preferred </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>0.11.5<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>runtime<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">scope</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> Uncomment this next dependency if you are using JDK 10 or earlier and you also want to use
   RSASSA-PSS (PS256, PS384, PS512) algorithms.JDK 11 or later does not require it for those algorithms:
&lt;dependency&gt;
    &lt;groupId&gt;org.bouncycastle&lt;/groupId&gt;
    &lt;artifactId&gt;bcprov-jdk15on&lt;/artifactId&gt;
    &lt;version&gt;1.70&lt;/version&gt;
    &lt;scope&gt;runtime&lt;/scope&gt;
&lt;/dependency&gt;
</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span></pre>
</div>
<p>如果您使用的是JDK 10或更早版本,并且还希望使用RSASSA-PSS(PS256、PS384、PS512)算法。JDK 11或更高版本不需要这些算法,需要依赖bcprov-jdk15on。</p>
<h2>2.4、生成JWT</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4;

</span><span style="color: rgba(0, 0, 255, 1)">import</span> io.jsonwebtoken.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Decoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Encoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.security.Keys;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.junit.jupiter.api.Test;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.test.context.SpringBootTest;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.crypto.SecretKey;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.nio.charset.StandardCharsets;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.Key;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Date;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.UUID;

@SpringBootTest
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> JWTTest {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过期毫秒时长</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> Expiration=24*60*60*1000<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String secretString="Zd+kZozTI5OgURtbegh8E6KTPghNNe/tEFwuLxd2UNw="<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成安全密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> SecretKey KEY =<span style="color: rgba(0, 0, 0, 1)"> Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">生成密钥</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> genKey(){
      Key key </span>=<span style="color: rgba(0, 0, 0, 1)"> Keys.secretKeyFor(SignatureAlgorithm.HS256);
      String secretString </span>=<span style="color: rgba(0, 0, 0, 1)"> Encoders.BASE64.encode(key.getEncoded());
      System.out.println(secretString);
    }

    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> creatJWT(){
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建一个Jwt构造器</span>
      JwtBuilder builder =<span style="color: rgba(0, 0, 0, 1)"> Jwts.builder();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签发时间</span>
      builder.setIssuedAt(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置过期时间</span>
      builder.setExpiration(<span style="color: rgba(0, 0, 255, 1)">new</span> Date(System.currentTimeMillis()+<span style="color: rgba(0, 0, 0, 1)">Expiration));
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置Id</span>
<span style="color: rgba(0, 0, 0, 1)">      builder.setId(UUID.randomUUID().toString());
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置主题</span>
      builder.setSubject("auth"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置自定义信息</span>
      builder.claim("username","zhangsan"<span style="color: rgba(0, 0, 0, 1)">);
      builder.claim(</span>"role","admin"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签名</span>
<span style="color: rgba(0, 0, 0, 1)">      builder.signWith(KEY);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成token字符串</span>
      String token=<span style="color: rgba(0, 0, 0, 1)">builder.compact();
      System.out.println(token);
    }
}</span></pre>
</div>
<p>运行结果:</p>
<p>eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njg2NDQ0MjksImV4cCI6MTY2ODczMDgyOSwianRpIjoiYTQ4NjJiNWYtZTg3NS00ZGQ5LTg1M2ItZTJmZjAyY2Y1NDViIiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiemhhbmdzYW4iLCJyb2xlIjoiYWRtaW4ifQ.VlEr3LZNc941vugUU8Cvxh5DX7h6rL1T3WSVZA81080</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221116152432183-1810570468.png" alt="" loading="lazy"></p>
<p>自定义密钥</p>
<p>您的密钥字符串是 Base64 编码的吗?如果是这样,请执行以下操作:</p>
<pre class="lang-java prettyprint-override"><code class="hljs"><span class="hljs-meta">@Value(<span class="hljs-string">"${jwt.token.secret}")
<span class="hljs-keyword">private String secret;

<span class="hljs-function"><span class="hljs-keyword">private Key <span class="hljs-title">getSigningKey<span class="hljs-params">() {
<span class="hljs-keyword">byte[] keyBytes = Decoders.BASE64.decode(<span class="hljs-keyword">this.secret);
<span class="hljs-keyword">return Keys.hmacShaKeyFor(keyBytes);
}

JwtToken.builder().value(Jwts.builder()
                .setClaims(createClaims(account))
                .setSubject(subject.toString())
                .setIssuedAt(Date.from(createdDateTime))
                .setExpiration(Date.from(expirationDateTime))
                .signWith(getSigningKey())
                .compact()).expiration(expirationDateTime.toString()).build()
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>如果您的密钥不是 base64 编码的(它可能应该是,因为例如,如果您使用原始密码,您的密钥可能不正确或格式不正确),您可以通过以下方式执行此操作:</p>
<pre class="lang-java prettyprint-override"><code class="hljs"><span class="hljs-function"><span class="hljs-keyword">private Key <span class="hljs-title">getSigningKey<span class="hljs-params">() {
<span class="hljs-keyword">byte[] keyBytes = <span class="hljs-keyword">this.secret.getBytes(StandardCharsets.UTF_8);
<span class="hljs-keyword">return Keys.hmacShaKeyFor(keyBytes);
}
</span></span></span></span></span></span></span></code></pre>
<p>但是,通常不建议使用第二个示例,因为这可能意味着您的密钥格式不佳。格式良好的安全随机密钥不是人类可读的,因此要将其存储为字符串,密钥字节通常首先进行 base64 编码。</p>
<p>从文档https://github.com/jwtk/jjwt#jws-key-create:</p>
<blockquote>
<p>如果要生成足够强的 SecretKey 以用于 JWT HMAC-SHA 算法,请使用<code>Keys.secretKeyFor(SignatureAlgorithm)</code>辅助方法:</p>
<pre class="lang-java prettyprint-override"><code class="hljs">SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); <span class="hljs-comment">//or HS384 or HS512
</span></code></pre>
<p>在幕后,JJWT 使用 JCA 提供程序的 KeyGenerator 为给定算法创建具有正确最小长度的安全随机密钥。</p>
<p>如果您有现有的 HMAC SHA SecretKey 的编码字节数组,则可以使用<code>Keys.hmacShaKeyFor</code>辅助方法。例如:</p>
<pre class="lang-java prettyprint-override"><code class="hljs"><span class="hljs-keyword">byte[] keyBytes = getSigningKeyFromApplicationConfiguration();
SecretKey key = Keys.hmacShaKeyFor(keyBytes);<br></span></code></pre>
</blockquote>
<h2>2.5、解析JWT</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4;

</span><span style="color: rgba(0, 0, 255, 1)">import</span> io.jsonwebtoken.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Decoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Encoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.security.Keys;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.junit.jupiter.api.Test;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.test.context.SpringBootTest;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.crypto.SecretKey;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.nio.charset.StandardCharsets;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.Key;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Date;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.UUID;

@SpringBootTest
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> JWTTest {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过期毫秒时长</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> Expiration=24*60*60*1000<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String secretString="Zd+kZozTI5OgURtbegh8E6KTPghNNe/tEFwuLxd2UNw="<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成安全密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> SecretKey KEY =<span style="color: rgba(0, 0, 0, 1)"> Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">生成密钥</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> genKey(){
      Key key </span>=<span style="color: rgba(0, 0, 0, 1)"> Keys.secretKeyFor(SignatureAlgorithm.HS256);
      String secretString </span>=<span style="color: rgba(0, 0, 0, 1)"> Encoders.BASE64.encode(key.getEncoded());
      System.out.println(secretString);
    }

    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> parseJWT(){
      String token</span>="eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njg2NDQwNjMsImV4cCI6MTY2ODczMDQ2MywianRpIjoiODI3N2FhMjgtMGJmOC00YjY0LWE3M2ItMjk3YWIyY2JhNDZmIiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiemhhbmdzYW4iLCJyb2xlIjoiYWRtaW4ifQ.oUX0iRjKMANNdFUmJdHgq3BJ_d4q54928p_leBx_JU0"<span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建解析器</span>
      JwtParserBuilder jwtParserBuilder =<span style="color: rgba(0, 0, 0, 1)"> Jwts.parserBuilder();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签名密钥</span>
<span style="color: rgba(0, 0, 0, 1)">      jwtParserBuilder.setSigningKey(KEY);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">解析token获得payload</span>
      Jws&lt;Claims&gt; claimsJws =<span style="color: rgba(0, 0, 0, 1)"> jwtParserBuilder.build().parseClaimsJws(token);
      System.out.println(claimsJws.getHeader());
      System.out.println(claimsJws.getBody());
      System.out.println(claimsJws.getSignature());
    }
}</span></pre>
</div>
<p>生成结果:</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221117082338805-300186339.png" alt="" loading="lazy"></p>
<p>JWT示例代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.zhangguo.jwtdemo;


</span><span style="color: rgba(0, 0, 255, 1)">import</span> io.jsonwebtoken.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Decoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Encoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.security.Keys;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.junit.jupiter.api.Test;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.beans.factory.annotation.Value;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.test.context.SpringBootTest;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.crypto.SecretKey;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.Key;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Date;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.UUID;

@SpringBootTest
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> JWTTest {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">密钥字符串</span>
    @Value("${jwt.token.secret}"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String KEYSTRING;

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">签名安全密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> SecretKey getKey() {
      SecretKey secretKey </span>=<span style="color: rgba(0, 0, 0, 1)"> Keys.hmacShaKeyFor(Decoders.BASE64.decode(KEYSTRING));
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> secretKey;
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">生成安全密钥,只执行一次</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> genSecretKey(){
      Key key </span>=<span style="color: rgba(0, 0, 0, 1)"> Keys.secretKeyFor(SignatureAlgorithm.HS256);
      String secretString </span>=<span style="color: rgba(0, 0, 0, 1)"> Encoders.BASE64.encode(key.getEncoded());
      System.out.println(secretString);
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过期毫秒数
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">public static final long EXPIRETIME=24*60*60*1000;</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">1天</span>

    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> EXPIRETIME=5*1000;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">5秒</span>
    <span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">创建JWT</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> createJWT(){
      System.out.println(KEYSTRING);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建一个JWT构造器</span>
      JwtBuilder builder =<span style="color: rgba(0, 0, 0, 1)"> Jwts.builder();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">header</span>
      builder.setHeaderParam("alg","HS256");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">签名加密算法的类型</span>
      builder.setHeaderParam("typ","JWT");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">token类型
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">payload</span>
      builder.setIssuedAt(<span style="color: rgba(0, 0, 255, 1)">new</span> Date());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">签发时间</span>
      builder.setExpiration(<span style="color: rgba(0, 0, 255, 1)">new</span> Date(System.currentTimeMillis()+EXPIRETIME));<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过期时间</span>
      builder.setId(UUID.randomUUID().toString());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">JWT ID</span>
      builder.setSubject("auth");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">主题</span>
      builder.claim("username","admin");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自定义信息</span>
      builder.claim("role","superadmin");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">角色,自定义信息</span>
      builder.signWith(getKey());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签名的密钥
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成签名</span>
      String token=<span style="color: rgba(0, 0, 0, 1)">builder.compact();
      System.out.println(token);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhdXRoIn0.TYKaWoixlcu8ma27Bf_i_pNujBLvwtkiX8WoXpUpg6I</span>
<span style="color: rgba(0, 0, 0, 1)">    }

    @Test
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> parseJWT(){
      String jwt</span>="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2Njg3Mzg4MDMsImV4cCI6MTY2ODczODgwOCwianRpIjoiOTNmNWJhODctMGQ0OC00MzhhLTg3MTAtMmMyNDc2OGRlZWY1Iiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiYWRtaW4iLCJyb2xlIjoic3VwZXJhZG1pbiJ9.d8kW9bwTsAOTEQrPhbzk8-1J5gZceXqXrfVYSr8mZ2M"<span style="color: rgba(0, 0, 0, 1)">;
      JwtParserBuilder jwtParserBuilder </span>= Jwts.parserBuilder();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">jwt解析器</span>
      jwtParserBuilder.setSigningKey(getKey());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签名的密钥</span>
      Jws&lt;Claims&gt; claimsJws = jwtParserBuilder.build().parseClaimsJws(jwt);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">解析内容</span>
<span style="color: rgba(0, 0, 0, 1)">
      System.out.println(</span>"头部:"+<span style="color: rgba(0, 0, 0, 1)">claimsJws.getHeader());
      System.out.println(</span>"数据:"+<span style="color: rgba(0, 0, 0, 1)">claimsJws.getBody());
      System.out.println(</span>"签名:"+<span style="color: rgba(0, 0, 0, 1)">claimsJws.getSignature());

      JwsHeader header </span>=<span style="color: rgba(0, 0, 0, 1)"> claimsJws.getHeader();
      Claims body </span>=<span style="color: rgba(0, 0, 0, 1)"> claimsJws.getBody();

      System.out.println(header.getAlgorithm());
      System.out.println(header.get(</span>"typ"<span style="color: rgba(0, 0, 0, 1)">));

      System.out.println(body.getExpiration());
      System.out.println(body.get(</span>"username"<span style="color: rgba(0, 0, 0, 1)">));

    }


}</span></pre>
</div>
<p>application.yaml文件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">jwt:
token:
    secret: </span>"hh1GG9NI67eAIGzjx5I5TuRB31jUFNpKzRhfLpqe4ZA="</pre>
</div>
<h1>三、Hutool工具类实现JWT</h1>
<h2 id="由来">3.1、由来</h2>
<p>从5.7.0开始,Hutool提供了零依赖的JWT(JSON Web Token)实现。</p>
<h2 id="jwt介绍">3.2、JWT介绍</h2>
<p>相关资料网络上非常多,可以自行搜索,简单点说JWT就是一种网络身份认证和信息交换格式。</p>
<h3 id="结构">3.2.1、结构</h3>
<ul>
<li>Header 头部信息,主要声明了JWT的签名算法等信息</li>
<li>Payload 载荷信息,主要承载了各种声明并传递明文数据</li>
<li>Signature 签名,拥有该部分的JWT被称为JWS,也就是签了名的JWS,用于校验数据</li>
</ul>
<p>整体结构是:</p>
<pre data-lang=""><code class="lang-">header.payload.signature</code></pre>
<h2 id="使用">3.3、使用</h2>
<p>JWT模块的核心主要是两个类:</p>
<ol>
<li><code>JWT</code>类用于链式生成、解析或验证JWT信息。</li>
<li><code>JWTUtil</code>类主要是JWT的一些工具封装,提供更加简洁的JWT生成、解析和验证工作</li>
</ol>
<h3 id="jwt生成">3.3.1、JWT生成</h3>
<ol>
<li>HS265(HmacSHA256)算法</li>
</ol>
<pre data-lang="java"><code class="lang-java"><span class="token comment">// 密钥
<span class="token keyword">byte<span class="token punctuation">[<span class="token punctuation">] key <span class="token operator">= <span class="token string">"1234567890"<span class="token punctuation">.<span class="token function">getBytes<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;

<span class="token class-name">String token <span class="token operator">= JWT<span class="token punctuation">.<span class="token function">create<span class="token punctuation">(<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"sub"<span class="token punctuation">, <span class="token string">"1234567890"<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"name"<span class="token punctuation">, <span class="token string">"looly"<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"admin"<span class="token punctuation">, <span class="token boolean">true<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setKey<span class="token punctuation">(key<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">sign<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>生成的内容为:</p>
<pre data-lang=""><code class="lang-">eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9.536690902d931d857d2f47d337ec81048ee09a8e71866bcc8404edbbcbf4cc40</code></pre>
<ol start="2">
<li>其他算法</li>
</ol>
<pre data-lang="java"><code class="lang-java"><span class="token comment">// 密钥
<span class="token keyword">byte<span class="token punctuation">[<span class="token punctuation">] key <span class="token operator">= <span class="token string">"1234567890"<span class="token punctuation">.<span class="token function">getBytes<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// SHA256withRSA
<span class="token class-name">String id <span class="token operator">= <span class="token string">"rs256"<span class="token punctuation">;
<span class="token class-name">JWTSigner signer <span class="token operator">= <span class="token class-name">JWTSignerUtil<span class="token punctuation">.<span class="token function">createSigner<span class="token punctuation">(id<span class="token punctuation">,
    <span class="token comment">// 随机生成密钥对,此处用户可自行读取`KeyPair`、公钥或私钥生成`JWTSigner`
    <span class="token class-name">KeyUtil<span class="token punctuation">.<span class="token function">generateKeyPair<span class="token punctuation">(<span class="token class-name">AlgorithmUtil<span class="token punctuation">.<span class="token function">getAlgorithm<span class="token punctuation">(id<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">;

<span class="token class-name">String token <span class="token operator">= JWT<span class="token punctuation">.<span class="token function">create<span class="token punctuation">(<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"sub"<span class="token punctuation">, <span class="token string">"1234567890"<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"name"<span class="token punctuation">, <span class="token string">"looly"<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"admin"<span class="token punctuation">, <span class="token boolean">true<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setSigner<span class="token punctuation">(signer<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">sign<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<ol start="3">
<li>不签名JWT</li>
</ol>
<pre data-lang="java"><code class="lang-java"><span class="token comment">// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9.
<span class="token class-name">String token <span class="token operator">= JWT<span class="token punctuation">.<span class="token function">create<span class="token punctuation">(<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"sub"<span class="token punctuation">, <span class="token string">"1234567890"<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"name"<span class="token punctuation">, <span class="token string">"looly"<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setPayload<span class="token punctuation">(<span class="token string">"admin"<span class="token punctuation">, <span class="token boolean">true<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">setSigner<span class="token punctuation">(<span class="token class-name">JWTSignerUtil<span class="token punctuation">.<span class="token function">none<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">)
    <span class="token punctuation">.<span class="token function">sign<span class="token punctuation">(<span class="token punctuation">)<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>示例代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package com.myproject.studentmis4;

import cn.hutool.jwt.JWT;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;
import java.util.UUID;

@SpringBootTest
public class HutoolJWTTest {

    </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] key="+6P1SPDJKQltJdSJq2W4IqPRLon/gQg2Z+dAMoqfYtU="<span style="color: rgba(0, 0, 0, 1)">.getBytes();

    @Test
    public </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> createJWT(){
      String token</span>=<span style="color: rgba(0, 0, 0, 1)">JWT.create()
                .setHeader(</span>"alg","HS256")<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">加密算法</span>
                .setHeader("typ","JWT")<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">类型</span>
                .setIssuedAt(<span style="color: rgba(0, 0, 255, 1)">new</span> Date())<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">签发日期</span>
                .setExpiresAt(<span style="color: rgba(0, 0, 255, 1)">new</span> Date(System.currentTimeMillis()+1000*60*60*24))<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过期时间</span>
                .setKey(key)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">密钥</span>
                .setJWTId(UUID.randomUUID().toString())<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">JWT编号</span>
                .setSubject("auth") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">主题</span>
                .setPayload("username","zhangsan123")<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自定义信息</span>
                .setPayload("role","admin") <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自定义信息</span>
                .sign();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成token</span>
<span style="color: rgba(0, 0, 0, 1)">      System.out.println(token);
    }
}</span></pre>
</div>
<p>运行结果:</p>
<div class="cnblogs_code">
<pre>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njg2NTY1MTYsImV4cCI6MTY2ODc0MjkxNiwianRpIjoiNjhkZmI2MDAtMGE2Yy00NjllLTg3MzYtNDViMDY0MGNkODQyIiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiemhhbmdzYW4xMjMiLCJyb2xlIjoiYWRtaW4ifQ.Ar2u1pZfLrj8cpvzCsgPp8u6gxA0I97jUp-uHorU2d0</pre>
</div>
<h3 id="jwt解析">3.3.2、JWT解析</h3>
<pre data-lang="java"><code class="lang-java"><span class="token class-name">String rightToken <span class="token operator">= <span class="token string">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." <span class="token operator">+
    <span class="token string">"eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9." <span class="token operator">+
    <span class="token string">"536690902d931d857d2f47d337ec81048ee09a8e71866bcc8404edbbcbf4cc40"<span class="token punctuation">;

<span class="token class-name">JWT jwt <span class="token operator">= JWT<span class="token punctuation">.<span class="token function">of<span class="token punctuation">(rightToken<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// JWT
jwt<span class="token punctuation">.<span class="token function">getHeader<span class="token punctuation">(<span class="token class-name">JWTHeader<span class="token punctuation">.TYPE<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// HS256
jwt<span class="token punctuation">.<span class="token function">getHeader<span class="token punctuation">(<span class="token class-name">JWTHeader<span class="token punctuation">.ALGORITHM<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// 1234567890
jwt<span class="token punctuation">.<span class="token function">getPayload<span class="token punctuation">(<span class="token string">"sub"<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// looly
jwt<span class="token punctuation">.<span class="token function">getPayload<span class="token punctuation">(<span class="token string">"name"<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// true
jwt<span class="token punctuation">.<span class="token function">getPayload<span class="token punctuation">(<span class="token string">"admin"<span class="token punctuation">)<span class="token punctuation">;<br><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">    @Test
    public </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> parseJWTInfo()
    {
       String token</span>="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njg2NTY1MTYsImV4cCI6MTY2ODc0MjkxNiwianRpIjoiNjhkZmI2MDAtMGE2Yy00NjllLTg3MzYtNDViMDY0MGNkODQyIiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiemhhbmdzYW4xMjMiLCJyb2xlIjoiYWRtaW4ifQ.Ar2u1pZfLrj8cpvzCsgPp8u6gxA0I97jUp-uHorU2d0"<span style="color: rgba(0, 0, 0, 1)">;
      JWT jwt </span>= JWT.of(token);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">解析jwt</span>

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">getAlgorithm:HS256</span>
      System.out.println("getAlgorithm:"+jwt.getAlgorithm());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">算法</span>
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">typ:JWT</span>
      System.out.println("typ:"+jwt.getHeader("typ"));<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">类型</span>

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">{"iat":1668656516,"exp":1668742916,"jti":"68dfb600-0a6c-469e-8736-45b0640cd842","sub":"auth","username":"zhangsan123","role":"admin"}</span>
<span style="color: rgba(0, 0, 0, 1)">      System.out.println(jwt.getPayloads());
    }</span></pre>
</div>
<h3 id="jwt验证">3.3.3、JWT验证</h3>
<ol>
<li>验证签名</li>
</ol>
<pre data-lang="java"><code class="lang-java"><span class="token class-name">String rightToken <span class="token operator">= <span class="token string">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." <span class="token operator">+
    <span class="token string">"eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9." <span class="token operator">+
    <span class="token string">"536690902d931d857d2f47d337ec81048ee09a8e71866bcc8404edbbcbf4cc40"<span class="token punctuation">;

<span class="token comment">// 密钥
<span class="token keyword">byte<span class="token punctuation">[<span class="token punctuation">] key <span class="token operator">= <span class="token string">"1234567890"<span class="token punctuation">.<span class="token function">getBytes<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// 默认验证HS265的算法
JWT<span class="token punctuation">.<span class="token function">of<span class="token punctuation">(rightToken<span class="token punctuation">)<span class="token punctuation">.<span class="token function">setKey<span class="token punctuation">(key<span class="token punctuation">)<span class="token punctuation">.<span class="token function">verify<span class="token punctuation">(<span class="token punctuation">)<br><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package com.myproject.studentmis4;

import cn.hutool.jwt.JWT;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;
import java.util.UUID;

@SpringBootTest
public class HutoolJWTTest {

    </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] key="+6P1SPDJKQltJdSJq2W4IqPRLon/gQg2Z+dAMoqfYtU="<span style="color: rgba(0, 0, 0, 1)">.getBytes();

    @Test
    public </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> parseJWTVerify()
    {
      String token</span>="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njg2NTY1MTYsImV4cCI6MTY2ODc0MjkxNiwianRpIjoiNjhkZmI2MDAtMGE2Yy00NjllLTg3MzYtNDViMDY0MGNkODQyIiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiemhhbmdzYW4xMjMiLCJyb2xlIjoiYWRtaW4ifQ.Ar2u1pZfLrj8cpvzCsgPp8u6gxA0I97jUp-uHorU2d0"<span style="color: rgba(0, 0, 0, 1)">;
      JWT.of(token).setKey(key).verify();</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">验证是否正确</span>
<span style="color: rgba(0, 0, 0, 1)">    }
}</span></pre>
</div>
<ol start="2">
<li>详细验证</li>
</ol>
<p>除了验证签名,Hutool提供了更加详细的验证:<code>validate</code>,主要包括:</p>
<ul>
<li>Token是否正确</li>
<li>生效时间不能晚于当前时间</li>
<li>失效时间不能早于当前时间</li>
<li>签发时间不能晚于当前时间</li>
</ul>
<p>使用方式如下:</p>
<pre data-lang="java"><code class="lang-java"><span class="token class-name">String token <span class="token operator">= <span class="token string">"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJNb0xpIiwiZXhwIjoxNjI0OTU4MDk0NTI4LCJpYXQiOjE2MjQ5NTgwMzQ1MjAsInVzZXIiOiJ1c2VyIn0.L0uB38p9sZrivbmP0VlDe--j_11YUXTu3TfHhfQhRKc"<span class="token punctuation">;

<span class="token keyword">byte<span class="token punctuation">[<span class="token punctuation">] key <span class="token operator">= <span class="token string">"1234567890"<span class="token punctuation">.<span class="token function">getBytes<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">boolean validate <span class="token operator">= JWT<span class="token punctuation">.<span class="token function">of<span class="token punctuation">(token<span class="token punctuation">)<span class="token punctuation">.<span class="token function">setKey<span class="token punctuation">(key<span class="token punctuation">)<span class="token punctuation">.<span class="token function">validate<span class="token punctuation">(<span class="token number">0<span class="token punctuation">)<span class="token punctuation">;<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h1>四、登录示例</h1>
<p>这里使用Vue3+TypeScript+VueRouter+Spring Boot+JWT实现一个简单的用户登录功能。</p>
<h2>4.1、前端</h2>
<h3>4.1.1、创建一个Vue3的项目</h3>
<p>创建一个Vue3项目,使用vue-cli,选择TypeScript,Babel</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221117145822477-317341642.png" alt="" width="943" height="491" loading="lazy"></p>
<h3>4.1.2、添加路由功能</h3>
<p>依赖vue-router,在命令行中使用npm i vue-router@next即可</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221117150046780-2014221628.png" alt="" width="656" height="197" loading="lazy"></p>
<p>&nbsp;src/router/index.ts</p>
<div class="cnblogs_code">
<pre>import {createRouter,createWebHashHistory,RouteRecordRaw} from 'vue-router'<span style="color: rgba(0, 0, 0, 1)">

const routes:RouteRecordRaw[]</span>=<span style="color: rgba(0, 0, 0, 1)">[{
    name:</span>"home"<span style="color: rgba(0, 0, 0, 1)">,
    path:</span>"/"<span style="color: rgba(0, 0, 0, 1)">,
    component:()</span>=&gt;import("../views/Home.vue"<span style="color: rgba(0, 0, 0, 1)">),
    meta:{
      requiredAuth:</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
    }
},{
    name:</span>"product"<span style="color: rgba(0, 0, 0, 1)">,
    path:</span>"/product"<span style="color: rgba(0, 0, 0, 1)">,
    component:()</span>=&gt;import("../views/Product.vue"<span style="color: rgba(0, 0, 0, 1)">),
    meta:{
      requiredAuth:</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
    }
},{
    name:</span>"main"<span style="color: rgba(0, 0, 0, 1)">,
    path:</span>"/main"<span style="color: rgba(0, 0, 0, 1)">,
    component:()</span>=&gt;import("../views/Main.vue"<span style="color: rgba(0, 0, 0, 1)">),
    meta:{
      requiredAuth:</span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
    }
},{
    name:</span>"login"<span style="color: rgba(0, 0, 0, 1)">,
    path:</span>"/login"<span style="color: rgba(0, 0, 0, 1)">,
    component:()</span>=&gt;import("../views/Login.vue"<span style="color: rgba(0, 0, 0, 1)">),
    meta:{
      requiredAuth:</span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
    }
}];

const router </span>=<span style="color: rgba(0, 0, 0, 1)"> createRouter({
    history:createWebHashHistory(),
    routes
})

router.beforeEach((to,from)</span>=&gt;<span style="color: rgba(0, 0, 0, 1)">{
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(to.name!=="login"&amp;&amp;to.meta.requiredAuth&amp;&amp;!<span style="color: rgba(0, 0, 0, 1)">isAuthorizated()){
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> {name:"login",query:{<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">:to.path}};
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
});

</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> isAuthorizated () {
    let USER</span>=localStorage.getItem("USER"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> !!<span style="color: rgba(0, 0, 0, 1)">USER;
}

export </span><span style="color: rgba(0, 0, 255, 1)">default</span> router;</pre>
</div>
<h3>4.1.3、创建组件</h3>
<p>views/Home.vue</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>当前位置:首页<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>欢迎您光临天狗商城<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="ts"</span><span style="color: rgba(255, 0, 0, 1)"> setup</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>views/Product.vue</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>当前位置:商品列表<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">ol</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>心相印抽纸卫生纸面巾纸餐巾纸纸巾纸巾抽 ¥8.9<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>家用陶瓷砂锅大容量耐高温明火陶瓷煲砂锅熬粥炖锅石锅煲汤砂锅 ¥29.99<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>周淼10.12 20点新品王牌款 可拆卸连帽 拼色90白鸭绒羽绒服 ¥729<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>家用创意桌面垃圾桶小号迷你茶几办公北欧网红ins床头带盖收纳桶 ¥5<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
      HEYGIRL黑哥 榛果巧棕!韩系经典正肩挺阔呢子大衣女50羊毛呢外套 ¥436.05
      </span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>60大包400张抽纸纸巾整箱家用实惠装卫生纸擦手纸餐巾纸面巾纸批 ¥13.1<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>10斤全效去渍自然馨香洗衣液家庭实惠装批发促销洗衣凝珠香味持久 ¥5.1<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>5双篮球袜男女同款中长筒棉袜四季ins潮百搭鲨鱼裤学生运动船袜 ¥8.9<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>SUN11 磨毛白色衬衫女秋冬加绒2022新款衬衣叠穿内搭打底长袖上衣 ¥249<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">li</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">ol</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="ts"</span><span style="color: rgba(255, 0, 0, 1)"> setup</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>views/Login.vue</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>当前位置:用户登录<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">fieldset</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">legend</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>用户信息<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">legend</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>帐号:<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">v-model</span><span style="color: rgba(0, 0, 255, 1)">="user.username"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>密码:<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">v-model</span><span style="color: rgba(0, 0, 255, 1)">="user.password"</span><span style="color: rgba(255, 0, 0, 1)"> type</span><span style="color: rgba(0, 0, 255, 1)">="password"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">button </span><span style="color: rgba(255, 0, 0, 1)">@click.prevent</span><span style="color: rgba(0, 0, 255, 1)">="login"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>登录<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">button</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">fieldset</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">setup lang</span><span style="color: rgba(0, 0, 255, 1)">="ts"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
import {inject} from </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">vue</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
import { useRoute, useRouter } from </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">vue-router</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
const axios: any </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> inject(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">axios</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);

let route </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> useRoute();
let router </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> useRouter();

let user </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> { username: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">""</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, password: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">""</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> };

</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> login() {
localStorage.removeItem(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">USER</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);

axios.post(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">login</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, user).then((response) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
    let result </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> response.data;
    console.log(result);
    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (result.code </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">==</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">1</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">&amp;&amp;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> result.jwt) {
      localStorage.setItem(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">USER</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, JSON.stringify(result));
      </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">获取上一个请求的路径,返回路径,如果没有则直接进入main</span>
<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">      let returnUrl </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> route.query.returnUrl </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">||</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/main</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
      router.replace({ path: returnUrl </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">""</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> });
    } </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">else</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
      alert(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">登录失败,请重试!</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
    }
});
}
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">style </span><span style="color: rgba(255, 0, 0, 1)">scoped</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>views/Main.vue</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>当前位置:个人中心(后台)<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">h3</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>欢迎您:{{ username }}<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>我的订单:{{ orders }}<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>收货地址:{{ address }}<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">p</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="ts"</span><span style="color: rgba(255, 0, 0, 1)"> setup</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
import { ref, getCurrentInstance, inject } from </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">vue</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
let ctx </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> getCurrentInstance();
const axios: any </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> inject(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">axios</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);

let USER </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> localStorage.getItem(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">USER</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
let username </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> ref(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">""</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
let orders </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> ref(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">""</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
let address </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> ref(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">""</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (USER) {
let userinfo </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> JSON.parse(USER);
username.value </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> userinfo.username;
}

let $http </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> ctx</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">?</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.appContext.config.globalProperties.$http;
$http
.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">user/order</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">)
.then((response: any) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
    orders.value </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> response.data.orders;
})
.</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">catch</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">((err) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {});

axios
.get(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">user/address</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">)
.then((response: any) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {
    address.value </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> response.data.address;
})
.</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">catch</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">((err) </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> {});
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>App.vue</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="container"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">h2</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>天狗商城<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">h2</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
      <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">router-link </span><span style="color: rgba(255, 0, 0, 1)">:to</span><span style="color: rgba(0, 0, 255, 1)">="{ name: 'home' }"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>首页<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">router-link</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)"> |
      </span><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">router-link </span><span style="color: rgba(255, 0, 0, 1)">:to</span><span style="color: rgba(0, 0, 255, 1)">="{ name: 'product' }"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>商品<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">router-link</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)"> |
      </span><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">router-link </span><span style="color: rgba(255, 0, 0, 1)">:to</span><span style="color: rgba(0, 0, 255, 1)">="{ name: 'main' }"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>我的<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">router-link</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)"> |
      </span><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">router-link </span><span style="color: rgba(255, 0, 0, 1)">:to</span><span style="color: rgba(0, 0, 255, 1)">="{ name: 'login' }"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>登录<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">router-link</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">router-view</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">router-view</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">template</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">lang</span><span style="color: rgba(0, 0, 255, 1)">="ts"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">
import { defineComponent } from </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">vue</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;

export </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">default</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> defineComponent({
name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">App</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">,
});
</span><span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>ts.config.js</p>
<div>"noImplicitAny": false,</div>
<h3>4.1.4、程序主文件</h3>
<div>main.ts</div>
<div>
<div class="cnblogs_code">
<pre>import { createApp } from 'vue'<span style="color: rgba(0, 0, 0, 1)">
import App from </span>'./App.vue'<span style="color: rgba(0, 0, 0, 1)">
import router from </span>'./router/index'<span style="color: rgba(0, 0, 0, 1)">
import axios from </span>'axios'<span style="color: rgba(0, 0, 0, 1)">;

axios.defaults.baseURL</span>="http://127.0.0.1:8089/api/"<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">response拦截器</span>
<span style="color: rgba(0, 0, 0, 1)">axios.interceptors.response.use(
    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (response) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (response.data.code === 1) {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">正常</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> response
      }

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (response.data.code === -1) {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">没有token</span>
<span style="color: rgba(0, 0, 0, 1)">      router.replace({
          name: </span>'login'<span style="color: rgba(0, 0, 0, 1)">
      });
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 错误信息的提示框</span>
      alert("错误:"+<span style="color: rgba(0, 0, 0, 1)">response.data.msg)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 将未处理的异常往外抛</span>
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 注:如果没有return Promise.reject(response),或者是直接return; 的话,当前请求的响应仍然会进行then中,只是它的response是undefined的。</span>
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 所以直接返回Promise.reject,在catch方法哪里就直接吃掉。</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Promise.reject(response)
    },
    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (error) {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> todo: 做一些其他日志记录处理</span>
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">alert('服务器错误,' + error);</span>
<span style="color: rgba(0, 0, 0, 1)">    }
)

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> request拦截器可对请求进行相应的处理</span>
<span style="color: rgba(0, 0, 0, 1)">axios.interceptors.request.use(
    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (config) {
      config.withCredentials </span>= <span style="color: rgba(0, 0, 255, 1)">true</span>
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 默认永不超时 0为永不超时</span>
      config.timeout = 0
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置请求的token</span>
      let USER = localStorage.getItem('USER'<span style="color: rgba(0, 0, 0, 1)">)
      let token</span>=""<span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(USER){
      let userinfo</span>=<span style="color: rgba(0, 0, 0, 1)">JSON.parse(USER);
      token</span>=<span style="color: rgba(0, 0, 0, 1)">userinfo.jwt;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (token) {
      config.headers </span>=<span style="color: rgba(0, 0, 0, 1)"> {token}
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> config
    },
    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (error) {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对请求错误做些什么</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Promise.reject(error)
    }
)


const app</span>=<span style="color: rgba(0, 0, 0, 1)">createApp(App);
app.config.globalProperties.$http</span>=<span style="color: rgba(0, 0, 0, 1)">axios;

app.provide(</span>"axios"<span style="color: rgba(0, 0, 0, 1)">,axios);

app.use(router);
app.mount(</span>'#app')</pre>
</div>
</div>
<h3>4.1.5、帮助文档</h3>
<p>axios帮助:https://www.axios-http.cn/docs/intro</p>
<h2>4.2、后台</h2>
<h3>&nbsp;4.2.1、工具类</h3>
<p>util.jwtUtil</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.util;

</span><span style="color: rgba(0, 0, 255, 1)">import</span> io.jsonwebtoken.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Decoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.io.Encoders;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io.jsonwebtoken.security.Keys;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.crypto.SecretKey;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.security.Key;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Date;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.HashMap;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.UUID;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> JWTUtil {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过期毫秒时长</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> Expiration=24*60*60*1000<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String secretString="Zd+kZozTI5OgURtbegh8E6KTPghNNe/tEFwuLxd2UNw="<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成安全密钥</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> SecretKey KEY =<span style="color: rgba(0, 0, 0, 1)"> Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">生成密钥</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> genKey(){
      Key key </span>=<span style="color: rgba(0, 0, 0, 1)"> Keys.secretKeyFor(SignatureAlgorithm.HS256);
      String secretString </span>=<span style="color: rgba(0, 0, 0, 1)"> Encoders.BASE64.encode(key.getEncoded());
      System.out.println(secretString);
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">创建JWT</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> String creatJWT(HashMap&lt;String,Object&gt;<span style="color: rgba(0, 0, 0, 1)"> payload){
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建一个Jwt构造器</span>
      JwtBuilder builder =<span style="color: rgba(0, 0, 0, 1)"> Jwts.builder();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签发时间</span>
      builder.setIssuedAt(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置过期时间</span>
      builder.setExpiration(<span style="color: rgba(0, 0, 255, 1)">new</span> Date(System.currentTimeMillis()+<span style="color: rgba(0, 0, 0, 1)">Expiration));
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置Id</span>
<span style="color: rgba(0, 0, 0, 1)">      builder.setId(UUID.randomUUID().toString());
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置主题</span>
      builder.setSubject("auth"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置自定义信息
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">builder.claim("username","zhangsan");
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">builder.claim("role","admin");</span>
<span style="color: rgba(0, 0, 0, 1)">      builder.addClaims(payload);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签名</span>
<span style="color: rgba(0, 0, 0, 1)">      builder.signWith(KEY);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">生成token字符串</span>
      String token=<span style="color: rgba(0, 0, 0, 1)">builder.compact();
      System.out.println(token);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> token;
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">解析JWT</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Jws&lt;Claims&gt;<span style="color: rgba(0, 0, 0, 1)"> parseJWT(String token){
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">String token="eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njg2NDQwNjMsImV4cCI6MTY2ODczMDQ2MywianRpIjoiODI3N2FhMjgtMGJmOC00YjY0LWE3M2ItMjk3YWIyY2JhNDZmIiwic3ViIjoiYXV0aCIsInVzZXJuYW1lIjoiemhhbmdzYW4iLCJyb2xlIjoiYWRtaW4ifQ.oUX0iRjKMANNdFUmJdHgq3BJ_d4q54928p_leBx_JU0";
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建解析器</span>
      JwtParserBuilder jwtParserBuilder =<span style="color: rgba(0, 0, 0, 1)"> Jwts.parserBuilder();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置签名密钥</span>
<span style="color: rgba(0, 0, 0, 1)">      jwtParserBuilder.setSigningKey(KEY);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">解析token获得payload</span>
      Jws&lt;Claims&gt; claimsJws =<span style="color: rgba(0, 0, 0, 1)"> jwtParserBuilder.build().parseClaimsJws(token);
      System.out.println(claimsJws.getHeader());
      System.out.println(claimsJws.getBody());
      System.out.println(claimsJws.getSignature());
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> claimsJws;
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">校验JWT</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> veryfiJWT(String token){
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">解析</span>
      <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            Jwts.parserBuilder().setSigningKey(KEY).build().parseClaimsJws(token);
      }
      </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception exp){
            exp.printStackTrace();
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
    }
}</span></pre>
</div>
<p>R.java&nbsp;封装返回数据对象</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.util;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.HashMap;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Map;

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 返回数据封装
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> R <span style="color: rgba(0, 0, 255, 1)">extends</span> HashMap&lt;String, Object&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> serialVersionUID = 1L<span style="color: rgba(0, 0, 0, 1)">;
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> R() {
      put(</span>"code", 1<span style="color: rgba(0, 0, 0, 1)">);
      put(</span>"msg", "success"<span style="color: rgba(0, 0, 0, 1)">);
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误时</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> R error() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> error(500, "未知异常,请联系管理员"<span style="color: rgba(0, 0, 0, 1)">);
    }
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> R error(String msg) {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> error(500<span style="color: rgba(0, 0, 0, 1)">, msg);
    }
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> R error(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> code, String msg) {
      R r </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> R();
      r.put(</span>"code"<span style="color: rgba(0, 0, 0, 1)">, code);
      r.put(</span>"msg"<span style="color: rgba(0, 0, 0, 1)">, msg);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> r;
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">成功时</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> R ok(String msg) {
      R r </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> R();
      r.put(</span>"msg"<span style="color: rgba(0, 0, 0, 1)">, msg);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> r;
    }
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> R ok(Map&lt;String, Object&gt;<span style="color: rgba(0, 0, 0, 1)"> map) {
      R r </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> R();
      r.putAll(map);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> r;
    }
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> R ok() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> R();
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> R ok(Object data) {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> R().put("data"<span style="color: rgba(0, 0, 0, 1)">,data);
    }

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> R put(String key, Object value) {
      </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.put(key, value);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
    }
}</span></pre>
</div>
<h3>4.2.2、实体类</h3>
<p>User&nbsp;用户实体</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.entity;

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">用户实体</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> User {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String username;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String password;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String code;

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> User(String username, String password, String code) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.password =<span style="color: rgba(0, 0, 0, 1)"> password;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.code =<span style="color: rgba(0, 0, 0, 1)"> code;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> User() {
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getUsername() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> username;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setUsername(String username) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getPassword() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> password;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setPassword(String password) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.password =<span style="color: rgba(0, 0, 0, 1)"> password;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getCode() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> code;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setCode(String code) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.code =<span style="color: rgba(0, 0, 0, 1)"> code;
    }
}</span></pre>
</div>
<p>UserIfno用户信息实体</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.entity;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Date;

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">用户信息</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> UserInfo {
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String username;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date expireTime;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String jwt;

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> UserInfo(String username, Date expireTime, String jwt) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.expireTime =<span style="color: rgba(0, 0, 0, 1)"> expireTime;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.jwt =<span style="color: rgba(0, 0, 0, 1)"> jwt;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> UserInfo() {
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getUsername() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> username;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setUsername(String username) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.username =<span style="color: rgba(0, 0, 0, 1)"> username;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getExpireTime() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> expireTime;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setExpireTime(Date expireTime) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.expireTime =<span style="color: rgba(0, 0, 0, 1)"> expireTime;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getJwt() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> jwt;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setJwt(String jwt) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.jwt =<span style="color: rgba(0, 0, 0, 1)"> jwt;
    }
}</span></pre>
</div>
<h3>4.2.3、全局过滤器</h3>
<p>CORS跨域</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.config;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Bean;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Configuration;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.web.cors.CorsConfiguration;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.web.cors.UrlBasedCorsConfigurationSource;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.web.filter.CorsFilter;

@Configuration
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> GlobalCorsConfig {

    @Bean
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> CorsFilter corsFilter() {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">1. 添加 CORS配置信息</span>
      CorsConfiguration config = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> CorsConfiguration();
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">放行哪些原始域</span>
      config.addAllowedOrigin("http://localhost:8080/"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">是否发送 Cookie</span>
      config.setAllowCredentials(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">放行哪些请求方式</span>
      config.addAllowedMethod("*"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">放行哪些原始请求头部信息</span>
      config.addAllowedHeader("*"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">暴露哪些头部信息</span>
      config.addExposedHeader("*"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2. 添加映射路径</span>
      UrlBasedCorsConfigurationSource corsConfigurationSource = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> UrlBasedCorsConfigurationSource();
      corsConfigurationSource.registerCorsConfiguration(</span>"/**"<span style="color: rgba(0, 0, 0, 1)">,config);
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">3. 返回新的CorsFilter</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> CorsFilter(corsConfigurationSource);
    }
}</span></pre>
</div>
<p>身份验证</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.config;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> cn.hutool.json.JSON;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> cn.hutool.json.JSONConverter;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> cn.hutool.json.JSONUtil;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.util.JWTUtil;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.util.R;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.context.annotation.Configuration;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.core.annotation.Order;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.web.filter.CorsFilter;

</span><span style="color: rgba(0, 0, 255, 1)">import</span> javax.servlet.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span> javax.servlet.annotation.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.servlet.http.HttpServletRequest;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.servlet.http.HttpServletResponse;
</span><span style="color: rgba(0, 0, 255, 1)">import</span> javax.swing.*<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.io.IOException;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.io.PrintWriter;

@WebFilter(filterName </span>= "AuthorizeFilter",urlPatterns = "/api/user/*"<span style="color: rgba(0, 0, 0, 1)">)
@Order(</span>99<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> AuthorizeFilter <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Filter {
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> init(FilterConfig config) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException {
    }

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> destroy() {
    }

    @Override
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doFilter(ServletRequest request, ServletResponse response, FilterChain chain) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException {

      HttpServletRequest httpServletRequest</span>=<span style="color: rgba(0, 0, 0, 1)"> (HttpServletRequest) request;
      HttpServletResponse httpServletResponse</span>=<span style="color: rgba(0, 0, 0, 1)"> (HttpServletResponse) response;

      httpServletResponse.setHeader(</span>"Access-Control-Allow-Origin", "http://localhost:8080"<span style="color: rgba(0, 0, 0, 1)">);
      httpServletResponse.setHeader(</span>"Access-Control-Allow-Headers", "Accept, Origin, XRequestedWith, Content-Type, LastModified,token"<span style="color: rgba(0, 0, 0, 1)">);
      httpServletResponse.setHeader(</span>"Access-Control-Allow-Credentials", "true"<span style="color: rgba(0, 0, 0, 1)">);
      httpServletResponse.setHeader(</span>"Access-Control-Allow-Methods"<span style="color: rgba(0, 0, 0, 1)">,
                </span>"GET, POST, PUT, DELETE, OPTIONS, HEAD"<span style="color: rgba(0, 0, 0, 1)">);
      String token</span>=httpServletRequest.getHeader("token"<span style="color: rgba(0, 0, 0, 1)">);

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果存在令牌</span>
      <span style="color: rgba(0, 0, 255, 1)">if</span>(token==<span style="color: rgba(0, 0, 255, 1)">null</span>||token.equals(""<span style="color: rgba(0, 0, 0, 1)">)){
            renderJson(httpServletResponse, R.error(</span>-1,"未授权"<span style="color: rgba(0, 0, 0, 1)">));
      }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                JWTUtil.veryfiJWT(token);
                chain.doFilter(request, response);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception exp){
                renderJson(httpServletResponse, R.error(</span>-2<span style="color: rgba(0, 0, 0, 1)">,exp.getMessage()));
            }
      }
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * 返回JSON数据
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> response
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> json
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> renderJson(HttpServletResponse response, Object json){
      response.setCharacterEncoding(</span>"UTF-8"<span style="color: rgba(0, 0, 0, 1)">);
      response.setContentType(</span>"application/json"<span style="color: rgba(0, 0, 0, 1)">);
      </span><span style="color: rgba(0, 0, 255, 1)">try</span> (PrintWriter writer =<span style="color: rgba(0, 0, 0, 1)"> response.getWriter()){
            writer.print(JSONUtil.toJsonStr(json));
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
            e.printStackTrace();
      }
    }
}</span></pre>
</div>
<h3>4.2.4、控制器</h3>
<p>登录控制器</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.controller;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> cn.hutool.core.lang.hash.Hash;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.entity.User;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.entity.UserInfo;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.util.JWTUtil;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4.util.R;
</span><span style="color: rgba(0, 0, 255, 1)">import</span> org.springframework.web.bind.annotation.*<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> javax.servlet.http.HttpServletRequest;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.HashMap;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Map;

@RestController
@RequestMapping(</span>"/api"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> LoginController {

    @PostMapping(</span>"/login"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> R login(@RequestBody User user){
      </span><span style="color: rgba(0, 0, 255, 1)">if</span>(user.getUsername().equals("admin")&amp;&amp;user.getPassword().equals("123456"<span style="color: rgba(0, 0, 0, 1)">)){
            HashMap</span>&lt;String,Object&gt; map=<span style="color: rgba(0, 0, 255, 1)">new</span> HashMap&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">();
            map.put(</span>"username"<span style="color: rgba(0, 0, 0, 1)">,user.getUsername());
             </span><span style="color: rgba(0, 0, 255, 1)">return</span> R.ok("登录成功"<span style="color: rgba(0, 0, 0, 1)">)
                  .put(</span>"username"<span style="color: rgba(0, 0, 0, 1)">,user.getUsername())
                  .put(</span>"jwt"<span style="color: rgba(0, 0, 0, 1)">, JWTUtil.creatJWT(map));
      }
      </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> R.error("登录失败!"<span style="color: rgba(0, 0, 0, 1)">);
      }
    }

    @GetMapping(</span>"/user/order"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> R getOrders(){
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> R.ok("请求成功").put("orders","这是当前用户的订单信息,从后台加载,模拟数据,需要权限才可以获取"<span style="color: rgba(0, 0, 0, 1)">);
    }

    @GetMapping(</span>"/user/address"<span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> R getAddress(){
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> R.ok("请求成功").put("address","这是当前用户的收货地址信息,从后台加载,模拟数据,需要权限才可以获取"<span style="color: rgba(0, 0, 0, 1)">);
    }

}</span></pre>
</div>
<h3>4.2.5、Application设置</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.myproject.studentmis4;

</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.SpringApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.autoconfigure.SpringBootApplication;
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Studentmis4Application {

    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
      SpringApplication.run(Studentmis4Application.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">, args);
    }

}</span></pre>
</div>
<h3>4.2.6、运行效果</h3>
<p>未登录时:</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221119134528755-1908281860.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;<img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221119134555797-1434102364.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;<img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221119134608977-718629838.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;<img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221119134622285-1537870283.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;登录后:</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221119134655461-120097606.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;伪造假的jwt</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202211/63651-20221119135152228-150715615.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h1>五、Shiro</h1>
<p>Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。</p>
<h2>5.1、主要功能</h2>
<p>三个核心组件:Subject,SecurityManager 和 Realms</p>
<p>1、Subject:<br>即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。</p>
<p>Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。</p>
<p>2、SecurityManager:<br>它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。</p>
<p>3、Realm:<br>Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。</p>
<p>从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。</p>
<p>Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。</p>
<h2>5.2、基本功能点</h2>
<p>Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份;<br>Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;<br>Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;<br>Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;<br>Web Support:Web 支持,可以非常容易的集成到 Web 环境;<br>Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;<br>Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;<br>Testing:提供测试支持;<br>Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;<br>Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了</p>
<h2>5.3、特点</h2>
<p>1、易于理解的 Java Security API</p>
<p>2、简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等)</p>
<p>3、对角色的简单的签权(访问控制),支持细粒度的签权</p>
<p>4、支持一级缓存,以提升应用程序的性能</p>
<p>5、内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境</p>
<p>6、异构客户端会话访问</p>
<p>7、非常简单的加密 API</p>
<p>8、不跟任何的框架或者容器捆绑,可以独立运行</p>
<h1>六、Spring Security</h1>
<h2>6.1、Spring Security</h2>
<p>Spring Security是一个灵活和强大的身份验证和访问控制框架,以确保基于Spring的Java Web应用程序的安全。</p>
<p>Spring Security是一个轻量级的安全框架,它确保基于Spring的应用程序提供身份验证和授权支持。它与Spring MVC有很好地集成,并配备了流行的安全算法实现捆绑在一起。</p>
<p>Spring Security 主要实现了Authentication(认证,解决who are you? ) 和 Access Control(访问控制,也就是what are you allowed to do?,也称为Authorization)。Spring Security在架构上将认证与授权分离,并提供了扩展点。“认证”是为用户建立一个其声明的角色的过程,这个角色可以一个用户、一个设备或者一个系统。“验证”指的是一个用户在你的应用中能够执行某个操作。在到达授权判断之前,角色已经在身份认证过程中建立了。</p>
<p>特点</p>
<p>Shiro能实现的,Spring Security 基本都能实现,依赖于Spring体系,但是好处是Spring全家桶的一员,集成上更加契合,在使用上,比Shiro略功能强大(但是一般Shiro够用)</p>
<h2>6.2、区别</h2>
<p>1、Shiro比Spring Security更容易使用,也就是实现上简单一些,同时基本的授权认证Shiro也基本够用</p>
<p>2、Spring Security社区支持度更高(但是安装Spring Security很难),Spring社区支持力度和更新维护上有优势,同时和Spring这一套的结合较好</p>
<p>3、Shiro 功能强大、且 简单、灵活。是Apache 下的项目比较可靠,且不跟任何的框架或者容器绑定,可以独立运行</p>
<p>个人理解</p>
<p>Shiro 首选 ,上手快 ,也足够用,自由度高,Spring Security中有的,Shiro也基本都有(项目没有使用Spring这一套,不用考虑,直接Shiro)</p>
<p>如果开发项目使用Spring这一套,用Spring Security可能更合适一些;虽然Spring Security 比较复杂,但与Spring 家族结合能力更强,是一个可以放心选择的框架结构</p>
<p>https://blog.csdn.net/MinggeQingchun/article/details/126414384</p>
<h1>七、示例</h1>
<p>&nbsp;</p>
<h1>八、视频</h1>
<p>【Vue3 下 + Vuex + Pinia + TypeScript + Router】&nbsp;https://www.bilibili.com/video/BV1C44y1X7Ud/?share_source=copy_web&amp;vd_source=475a31f3c5d6353a782007cd4c638a8a</p>
<p>【Vue3 上 + Vuex + Pinia + TypeScript + Router】&nbsp;https://www.bilibili.com/video/BV1at4y1F75D/?share_source=copy_web&amp;vd_source=475a31f3c5d6353a782007cd4c638a8a</p><br><br>
来源:https://www.cnblogs.com/best/p/16895150.html
頁: [1]
查看完整版本: SpringBoot学习笔记(八)——JWT、(Vue3、Axios、Vue-Router、TypeScript实现授权与验证示例)