<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>醋溜折耳根</title>
  
  
  <link href="https://enoliu.github.io/atom.xml" rel="self"/>
  
  <link href="https://enoliu.github.io/"/>
  <updated>2022-08-11T08:58:37.305Z</updated>
  <id>https://enoliu.github.io/</id>
  
  <author>
    <name>Enoliu</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>golang-jwt/jwt使用手册</title>
    <link href="https://enoliu.github.io/2022/08/11/golang-jwt-jwt%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C/"/>
    <id>https://enoliu.github.io/2022/08/11/golang-jwt-jwt%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C/</id>
    <published>2022-08-11T06:06:09.000Z</published>
    <updated>2022-08-11T08:58:37.305Z</updated>
    
    <content type="html"><![CDATA[<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>当前最新版本为<code>v4</code>版本，新增了 Go 模块支持，但依旧保留了向后兼容性</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go get -u github.com/golang-jwt/jwt/v4</span><br></pre></td></tr></table></figure><h2 id="官方规定的一些声明Claims（载荷）"><a href="#官方规定的一些声明Claims（载荷）" class="headerlink" title="官方规定的一些声明Claims（载荷）"></a>官方规定的一些声明Claims（载荷）</h2><p>这些声明都是可选的，不强制的。只是为后续操作提供方便，可操作性的起始点数据</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> RegisteredClaims <span class="keyword">struct</span> &#123;</span><br><span class="line"><span class="comment">// the `iss` (Issuer) claim. 发行人：声明JWT的发行主体，一般固定为应用名称</span></span><br><span class="line">Issuer <span class="type">string</span> <span class="string">`json:&quot;iss,omitempty&quot;`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// the `sub` (Subject) claim. 主题：声明JWT的发行主题，主题值必须全局惟一的</span></span><br><span class="line">Subject <span class="type">string</span> <span class="string">`json:&quot;sub,omitempty&quot;`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// the `aud` (Audience) claim. 接收者：具体的客户端应用</span></span><br><span class="line">Audience ClaimStrings <span class="string">`json:&quot;aud,omitempty&quot;`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// the `exp` (Expiration Time) claim. 到期时间</span></span><br><span class="line">ExpiresAt *NumericDate <span class="string">`json:&quot;exp,omitempty&quot;`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// the `nbf` (Not Before) claim. 可用开始时间</span></span><br><span class="line">NotBefore *NumericDate <span class="string">`json:&quot;nbf,omitempty&quot;`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// the `iat` (Issued At) claim. 颁发时间</span></span><br><span class="line">IssuedAt *NumericDate <span class="string">`json:&quot;iat,omitempty&quot;`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// the `jti` (JWT ID) claim. JWT的唯一标识符，注意：和sub是不一样的概念</span></span><br><span class="line">ID <span class="type">string</span> <span class="string">`json:&quot;jti,omitempty&quot;`</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="对称加密"><a href="#对称加密" class="headerlink" title="对称加密"></a>对称加密</h2><p>（例如 <code>HSA</code>）仅使用一个密钥。这可能是最简单的签名方法，因为任何[]byte都可以用作有效的秘密。它们在计算上的使用速度也略快一些，尽管这很少有关系。当令牌的生产者和消费者都受信任，甚至是同一个系统时，对称签名方法效果最好。由于相同的密钥用于签名和验证令牌，因此您无法轻松分发密钥以进行验证。</p><h3 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h3><h4 id="生成token"><a href="#生成token" class="headerlink" title="生成token"></a>生成token</h4><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> signKey = <span class="string">&quot;this is your sign key&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// CustomClaims 自定义jwt的claims信息，包含官方注册的claims</span></span><br><span class="line"><span class="keyword">type</span> CustomClaims <span class="keyword">struct</span> &#123;</span><br><span class="line">jwt.RegisteredClaims</span><br><span class="line">Email <span class="type">string</span> <span class="string">`json:&quot;email&quot;`</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// CreateToken Create a jwt token from request.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*helloApi)</span></span> CreateToken(r *ghttp.Request) &#123;</span><br><span class="line">nowTime := time.Now()</span><br><span class="line">userId := <span class="string">&quot;123456&quot;</span>             <span class="comment">// 用户ID（唯一标识）</span></span><br><span class="line">appName := <span class="string">&quot;coolcar&quot;</span>           <span class="comment">// 应用名称</span></span><br><span class="line">expireIn := <span class="number">7</span> * <span class="number">24</span> * time.Hour <span class="comment">// 有效时长</span></span><br><span class="line"><span class="keyword">var</span> token = jwt.NewWithClaims(jwt.SigningMethodHS256, CustomClaims&#123;</span><br><span class="line">RegisteredClaims: jwt.RegisteredClaims&#123;</span><br><span class="line">Issuer:    appName,</span><br><span class="line">Subject:   userId,</span><br><span class="line">ExpiresAt: jwt.NewNumericDate(nowTime.Add(expireIn)),</span><br><span class="line">NotBefore: jwt.NewNumericDate(nowTime),</span><br><span class="line">IssuedAt:  jwt.NewNumericDate(nowTime),</span><br><span class="line">&#125;,</span><br><span class="line">Email: <span class="string">&quot;595929049@qq.com&quot;</span>, <span class="comment">// 自定义的claims</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">tokenString, _ := token.SignedString([]<span class="type">byte</span>(signKey))</span><br><span class="line"></span><br><span class="line">_ = r.Response.WriteJson(g.Map&#123;</span><br><span class="line"><span class="string">&quot;token&quot;</span>:     tokenString,</span><br><span class="line"><span class="string">&quot;expire_in&quot;</span>: <span class="type">int</span>(expireIn.Seconds()),</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="使用token"><a href="#使用token" class="headerlink" title="使用token"></a>使用token</h4><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*helloApi)</span></span> ParseToken(r *ghttp.Request) &#123;</span><br><span class="line">tokenString := r.GetHeader(<span class="string">&quot;authorization&quot;</span>)</span><br><span class="line"><span class="comment">// 注意区分strings.TrimPrefix 和 strings.TrimLeft的区别</span></span><br><span class="line">tokenString = strings.TrimPrefix(tokenString, <span class="string">&quot;Bearer &quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 加入claims的验证</span></span><br><span class="line">token, err := jwt.ParseWithClaims(tokenString, &amp;CustomClaims&#123;&#125;, <span class="function"><span class="keyword">func</span><span class="params">(token *jwt.Token)</span></span> (<span class="keyword">interface</span>&#123;&#125;, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> []<span class="type">byte</span>(signKey), <span class="literal">nil</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">claims, ok := token.Claims.(*CustomClaims)</span><br><span class="line"><span class="keyword">if</span> !ok || !token.Valid &#123;</span><br><span class="line"><span class="keyword">if</span> errors.Is(err, jwt.ErrTokenMalformed) &#123;</span><br><span class="line">r.Response.WriteExit(<span class="string">&quot;That&#x27;s not even a token&quot;</span>)</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) &#123;</span><br><span class="line"><span class="comment">// Token is either expired or not active yet</span></span><br><span class="line">r.Response.WriteExit(<span class="string">&quot;Timing is everything&quot;</span>)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">r.Response.WriteExit(<span class="string">&quot;Couldn&#x27;t handle this token:&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">_ = r.Response.WriteJson(g.Map&#123;</span><br><span class="line"><span class="string">&quot;email&quot;</span>:    claims.Email,</span><br><span class="line"><span class="string">&quot;user_id&quot;</span>:  claims.Subject,</span><br><span class="line"><span class="string">&quot;app_name&quot;</span>: claims.Issuer,</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="非对称加密"><a href="#非对称加密" class="headerlink" title="非对称加密"></a>非对称加密</h2><p>（例如 <code>RSA</code>）使用不同的密钥来签名和验证令牌。这使得使用私钥生成令牌成为可能，并允许任何消费者访问公钥进行验证。</p><h3 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h3><h4 id="生成token-1"><a href="#生成token-1" class="headerlink" title="生成token"></a>生成token</h4><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> privateKey = <span class="string">`-----BEGIN PRIVATE KEY-----</span></span><br><span class="line"><span class="string">MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAs57i3yugK3vbC6G2</span></span><br><span class="line"><span class="string">UVTw8Vk7BMARaSN1W6ouF59X2N/8ocMbchNxofEudf/2X6Us2V1srFgvPC/CE1N2</span></span><br><span class="line"><span class="string">ncDMXwIDAQABAkAT6VwbAzoJN/yrSGzujSz8hDi/qQ8FCbI7zBy576cMWnCKFwTT</span></span><br><span class="line"><span class="string">KDWfxaW9sISqsiHFoBiq0EHj99H0/x6o014pAiEA4g7yxcu2m6yOQSlaWsA9vHnd</span></span><br><span class="line"><span class="string">vuhrPcgXWQfQTqDGodUCIQDLaVrbH4H71uV/svegy4dG8T7U4c8/mil3x9qOowPb</span></span><br><span class="line"><span class="string">YwIhALn7DmUIyn2dI5Qcj4emLaSIppTP5pr3qa3HretifsjZAiBHkdsw7CYdCSCY</span></span><br><span class="line"><span class="string">zMyKG/KOCIX1+zmjhEeA6KXCuCK8RwIgC2synVWxCtKMJdj782Ksw5+rh8fM56Si</span></span><br><span class="line"><span class="string">tmgaHfusqJw=</span></span><br><span class="line"><span class="string">-----END PRIVATE KEY-----`</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// CustomClaims 自定义jwt的claims信息，包含官方注册的claims</span></span><br><span class="line"><span class="keyword">type</span> CustomClaims <span class="keyword">struct</span> &#123;</span><br><span class="line">jwt.RegisteredClaims</span><br><span class="line">Email <span class="type">string</span> <span class="string">`json:&quot;email&quot;`</span> <span class="comment">// 自定义的claims</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// CreateToken Create a jwt token from request.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*helloApi)</span></span> CreateToken(r *ghttp.Request) &#123;</span><br><span class="line">nowTime := time.Now()</span><br><span class="line">userId := <span class="string">&quot;123456&quot;</span>             <span class="comment">// 用户ID（唯一标识）</span></span><br><span class="line">appName := <span class="string">&quot;coolcar&quot;</span>           <span class="comment">// 应用名称</span></span><br><span class="line">expireIn := <span class="number">7</span> * <span class="number">24</span> * time.Hour <span class="comment">// 有效时长</span></span><br><span class="line"><span class="keyword">var</span> token = jwt.NewWithClaims(jwt.SigningMethodRS256, CustomClaims&#123;</span><br><span class="line">RegisteredClaims: jwt.RegisteredClaims&#123;</span><br><span class="line">Issuer:    appName,</span><br><span class="line">Subject:   userId,</span><br><span class="line">ExpiresAt: jwt.NewNumericDate(nowTime.Add(expireIn)),</span><br><span class="line">NotBefore: jwt.NewNumericDate(nowTime),</span><br><span class="line">IssuedAt:  jwt.NewNumericDate(nowTime),</span><br><span class="line">&#125;,</span><br><span class="line">Email: <span class="string">&quot;595929049@qq.com&quot;</span>, <span class="comment">// 自定义的claims</span></span><br><span class="line">&#125;)</span><br><span class="line">privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]<span class="type">byte</span>(privateKey))</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatal(<span class="string">&quot;parse rsa private key error :&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">tokenString, _ := token.SignedString(privateKey)</span><br><span class="line"></span><br><span class="line">_ = r.Response.WriteJson(g.Map&#123;</span><br><span class="line"><span class="string">&quot;token&quot;</span>:     tokenString,</span><br><span class="line"><span class="string">&quot;expire_in&quot;</span>: <span class="type">int</span>(expireIn.Seconds()),</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h5><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"><span class="attr">&quot;expire_in&quot;</span><span class="punctuation">:</span> <span class="number">604800</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">&quot;token&quot;</span><span class="punctuation">:</span> <span class="string">&quot;eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjb29sY2FyIiwic3ViIjoiMTIzNDU2IiwiZXhwIjoxNjYwODA2OTYzLCJuYmYiOjE2NjAyMDIxNjMsImlhdCI6MTY2MDIwMjE2MywiZW1haWwiOiI1OTU5MjkwNDlAcXEuY29tIn0.cr4KPReapVGyiFjmNqGPEIIUrFLSO8PgpoWVFmMnWEzFzd9RBpwJdSLywcE5k7nrwpR9TexPk-hRnxgBta3t5w&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h4 id="使用token-1"><a href="#使用token-1" class="headerlink" title="使用token"></a>使用token</h4><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> publicKey = <span class="string">`-----BEGIN PUBLIC KEY-----</span></span><br><span class="line"><span class="string">MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALOe4t8roCt72wuhtlFU8PFZOwTAEWkj</span></span><br><span class="line"><span class="string">dVuqLhefV9jf/KHDG3ITcaHxLnX/9l+lLNldbKxYLzwvwhNTdp3AzF8CAwEAAQ==</span></span><br><span class="line"><span class="string">-----END PUBLIC KEY-----`</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(*helloApi)</span></span> ParseToken(r *ghttp.Request) &#123;</span><br><span class="line">tokenString := r.GetHeader(<span class="string">&quot;authorization&quot;</span>)</span><br><span class="line"><span class="comment">// 注意区分strings.TrimPrefix 和 strings.TrimLeft的区别</span></span><br><span class="line">tokenString = strings.TrimPrefix(tokenString, <span class="string">&quot;Bearer &quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface&#123;&#125;, error) &#123;</span></span><br><span class="line"><span class="comment">//return jwt.ParseRSAPublicKeyFromPEM([]byte(publicKey))</span></span><br><span class="line"><span class="comment">//&#125;)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 加入claims的验证</span></span><br><span class="line">token, err := jwt.ParseWithClaims(tokenString, &amp;CustomClaims&#123;&#125;, <span class="function"><span class="keyword">func</span><span class="params">(token *jwt.Token)</span></span> (<span class="keyword">interface</span>&#123;&#125;, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> jwt.ParseRSAPublicKeyFromPEM([]<span class="type">byte</span>(publicKey))</span><br><span class="line">&#125;)</span><br><span class="line">    </span><br><span class="line">claims, ok := token.Claims.(*CustomClaims)</span><br><span class="line"><span class="keyword">if</span> !ok || !token.Valid &#123;</span><br><span class="line"><span class="keyword">if</span> errors.Is(err, jwt.ErrTokenMalformed) &#123;</span><br><span class="line">r.Response.WriteExit(<span class="string">&quot;That&#x27;s not even a token&quot;</span>)</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) &#123;</span><br><span class="line"><span class="comment">// Token is either expired or not active yet</span></span><br><span class="line">r.Response.WriteExit(<span class="string">&quot;Timing is everything&quot;</span>)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">r.Response.WriteExit(<span class="string">&quot;Couldn&#x27;t handle this token:&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">_ = r.Response.WriteJson(g.Map&#123;</span><br><span class="line"><span class="string">&quot;email&quot;</span>:    claims.Email,</span><br><span class="line"><span class="string">&quot;user_id&quot;</span>:  claims.Subject,</span><br><span class="line"><span class="string">&quot;app_name&quot;</span>: claims.Issuer,</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="结果-1"><a href="#结果-1" class="headerlink" title="结果"></a>结果</h5><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line"><span class="attr">&quot;app_name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;coolcar&quot;</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">&quot;email&quot;</span><span class="punctuation">:</span> <span class="string">&quot;595929049@qq.com&quot;</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">&quot;user_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;123456&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;安装&quot;&gt;&lt;a href=&quot;#安装&quot; class=&quot;headerlink&quot; title=&quot;安装&quot;&gt;&lt;/a&gt;安装&lt;/h2&gt;&lt;p&gt;当前最新版本为&lt;code&gt;v4&lt;/code&gt;版本，新增了 Go 模块支持，但依旧保留了向后兼容性&lt;/p&gt;
&lt;figure class=&quot;hi</summary>
      
    
    
    
    <category term="Golang" scheme="https://enoliu.github.io/categories/Golang/"/>
    
    
    <category term="jwt" scheme="https://enoliu.github.io/tags/jwt/"/>
    
  </entry>
  
  <entry>
    <title>[golang]grpc-gateway使用入门</title>
    <link href="https://enoliu.github.io/2022/07/22/golang-grpc-gateway%E4%BD%BF%E7%94%A8%E5%85%A5%E9%97%A8/"/>
    <id>https://enoliu.github.io/2022/07/22/golang-grpc-gateway%E4%BD%BF%E7%94%A8%E5%85%A5%E9%97%A8/</id>
    <published>2022-07-22T06:10:08.000Z</published>
    <updated>2022-07-22T08:40:08.087Z</updated>
    
    <content type="html"><![CDATA[<h1 id="gRPC-Gateway介绍"><a href="#gRPC-Gateway介绍" class="headerlink" title="gRPC-Gateway介绍"></a>gRPC-Gateway介绍</h1><h1 id="gRPC简单实现"><a href="#gRPC简单实现" class="headerlink" title="gRPC简单实现"></a>gRPC简单实现</h1><ol><li><p>定义proto文件</p><figure class="highlight protobuf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">syntax = <span class="string">&quot;proto3&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> auth.v1;</span><br><span class="line"></span><br><span class="line"><span class="keyword">option</span> go_package = <span class="string">&quot;coolcar/auth/api/gen/v1;authpb&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// import &quot;google/api/annotations.proto&quot;;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">service </span><span class="title class_">AuthService</span> &#123;</span><br><span class="line">    <span class="comment">// 注解方式</span></span><br><span class="line">    <span class="comment">// rpc Login (LoginRequest) returns (LoginResponse) &#123;</span></span><br><span class="line">    <span class="comment">//     option(google.api.http) = &#123;</span></span><br><span class="line">    <span class="comment">//         post: &quot;/v1/auth/login&quot;,</span></span><br><span class="line">    <span class="comment">//         body: &quot;*&quot;</span></span><br><span class="line">    <span class="comment">//     &#125;;</span></span><br><span class="line">    <span class="comment">// &#125;;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 也可以通过auth.yaml配置文件形式 </span></span><br><span class="line">    <span class="function"><span class="keyword">rpc</span> Login (LoginRequest) <span class="keyword">returns</span> (LoginResponse)</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">message </span><span class="title class_">LoginRequest</span> &#123;</span><br><span class="line">    <span class="type">string</span> code = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">message </span><span class="title class_">LoginResponse</span> &#123;</span><br><span class="line">    <span class="type">string</span> access_token = <span class="number">1</span>;</span><br><span class="line">    <span class="type">int32</span> expires_in = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>根据文件生成相应代码  </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">go程序代码</span></span><br><span class="line">protoc -I . --go_out gen/v1 --go_opt paths=source_relative auth.proto</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">grpc服务代码</span></span><br><span class="line">protoc -I . --go-grpc_out gen/v1 --go-grpc_opt paths=source_relative auth.proto</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">grpc-gateway代码</span></span><br><span class="line">protoc -I . --grpc-gateway_out gen/v1 --grpc-gateway_opt paths=source_relative,grpc_api_configuration=auth.yaml  auth.proto</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">三个命令可合为一个</span></span><br><span class="line">protoc -I . \</span><br><span class="line">--go_out gen/v1 \</span><br><span class="line">--go_opt paths=source_relative \</span><br><span class="line">--go-grpc_out gen/v1 \</span><br><span class="line">--go-grpc_opt paths=source_relative \</span><br><span class="line">--grpc-gateway_out gen/v1 \</span><br><span class="line">--grpc-gateway_opt paths=source_relative,grpc_api_configuration=auth.yaml \</span><br><span class="line">auth.proto</span><br></pre></td></tr></table></figure><p>生成代码文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">├── auth.proto  # proto</span><br><span class="line">├── auth.yaml   # gateway 配置文件</span><br><span class="line">└── gen</span><br><span class="line">    └── v1</span><br><span class="line">        ├── auth_grpc.pb.go # grpc服务方法</span><br><span class="line">        ├── auth.pb.go      # 消息体文件</span><br><span class="line">        └── auth.pb.gw.go   # grpc-gateway代理文件</span><br></pre></td></tr></table></figure></li><li><p>实现grpc服务接口方法</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> auth</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;context&quot;</span></span><br><span class="line">authpb <span class="string">&quot;coolcar/auth/api/gen/v1&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Service <span class="keyword">struct</span> &#123;</span><br><span class="line"><span class="comment">// 不要问，继承这个空服务就行了。看稳定是为了兼容后续</span></span><br><span class="line">*authpb.UnimplementedAuthServiceServer</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(s *Service)</span></span> Login(ctx context.Context, req *authpb.LoginRequest) (*authpb.LoginResponse, <span class="type">error</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> &amp;authpb.LoginResponse&#123;</span><br><span class="line">AccessToken: <span class="string">&quot;access_token for &quot;</span> + req.Code,</span><br><span class="line">ExpiresIn:   <span class="number">7200</span>,</span><br><span class="line">&#125;, <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>拉起grpc服务</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">authpb <span class="string">&quot;coolcar/auth/api/gen/v1&quot;</span></span><br><span class="line"><span class="string">&quot;coolcar/auth/auth&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line"><span class="string">&quot;net&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="string">&quot;google.golang.org/grpc&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="comment">// 监听TCP端口号</span></span><br><span class="line">lis, err := net.Listen(<span class="string">&quot;tcp&quot;</span>, <span class="string">&quot;:8081&quot;</span>)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatal(err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 创建一个grpc服务</span></span><br><span class="line">s := grpc.NewServer()</span><br><span class="line"><span class="comment">// 注册grpc服务</span></span><br><span class="line">authpb.RegisterAuthServiceServer(s, &amp;auth.Service&#123;&#125;)</span><br><span class="line"><span class="comment">// 拉起服务</span></span><br><span class="line">log.Fatal(s.Serve(lis))</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>调用grpc服务</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">startClient</span><span class="params">()</span></span> &#123;</span><br><span class="line">conn, err := grpc.Dial(<span class="string">&quot;localhost:8081&quot;</span>, grpc.WithTransportCredentials(insecure.NewCredentials()))</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatalln(<span class="string">&quot;连接服务失败:&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">defer</span> conn.Close()</span><br><span class="line"></span><br><span class="line">client := authpb.NewAuthServiceClient(conn)</span><br><span class="line"></span><br><span class="line">ctx, cancel := context.WithTimeout(context.Background(), time.Second)</span><br><span class="line"><span class="keyword">defer</span> cancel()</span><br><span class="line">rsp, err := client.Login(ctx, &amp;authpb.LoginRequest&#123;Code: <span class="string">&quot;123456&quot;</span>&#125;)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatalln(<span class="string">&quot;调用方法失败：&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">fmt.Printf(<span class="string">&quot;调用结果为: access_token = %v, expire_in = %v&quot;</span>, rsp.AccessToken, rsp.ExpiresIn)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h1 id="为gRPC服务添加Gateway"><a href="#为gRPC服务添加Gateway" class="headerlink" title="为gRPC服务添加Gateway"></a>为gRPC服务添加Gateway</h1><p>前端程序不能直接调用grpc服务，所以使用grpc-gateway网关反向代理</p><ol><li>方式一<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">registerHandler</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="comment">// 创建一个客户端连接到grpc服务器，然后用grpc-gateway代理请求反向代理到这个客户端</span></span><br><span class="line">conn, err := grpc.DialContext(</span><br><span class="line">context.Background(),</span><br><span class="line"><span class="string">&quot;localhost:8081&quot;</span>,</span><br><span class="line">grpc.WithBlock(),</span><br><span class="line">grpc.WithTransportCredentials(insecure.NewCredentials()),</span><br><span class="line">)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatalln(<span class="string">&quot;连接grpc服务器失败&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建路由处理器</span></span><br><span class="line">gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(</span><br><span class="line">runtime.MIMEWildcard,</span><br><span class="line">&amp;runtime.JSONPb&#123;</span><br><span class="line">MarshalOptions: protojson.MarshalOptions&#123;</span><br><span class="line">Multiline:       <span class="literal">false</span>, <span class="comment">// 多行显示，Indent</span></span><br><span class="line">Indent:          <span class="string">&quot;&quot;</span>,    <span class="comment">// 缩进</span></span><br><span class="line">AllowPartial:    <span class="literal">false</span>,</span><br><span class="line">UseProtoNames:   <span class="literal">false</span>, <span class="comment">// 使用原型proto里定义的字段名</span></span><br><span class="line">UseEnumNumbers:  <span class="literal">false</span>, <span class="comment">// 使用枚举enum对应的数字</span></span><br><span class="line">EmitUnpopulated: <span class="literal">false</span>, <span class="comment">// 是否返回空（未填充）的字段</span></span><br><span class="line">Resolver:        <span class="literal">nil</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;,</span><br><span class="line">))</span><br><span class="line"></span><br><span class="line">err = authpb.RegisterAuthServiceHandler(context.Background(), gwmux, conn)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatal(<span class="string">&quot;注册grpc-gateway代理失败：&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听http服务</span></span><br><span class="line">log.Fatal(<span class="string">&quot;启动http服务失败:&quot;</span>, http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, gwmux))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li>方式二<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">registerHandlerFromEndPoint</span><span class="params">()</span></span> &#123;</span><br><span class="line">ctx, cancel := context.WithCancel(context.Background())</span><br><span class="line"><span class="keyword">defer</span> cancel()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建路由处理器</span></span><br><span class="line">gwmux := runtime.NewServeMux(runtime.WithMarshalerOption(</span><br><span class="line">runtime.MIMEWildcard,</span><br><span class="line"><span class="comment">// JSONPb对JSON进行编组/解组。与JSONBuiltin不同，它支持protobuf的全部功能。</span></span><br><span class="line">&amp;runtime.JSONPb&#123;</span><br><span class="line">MarshalOptions: protojson.MarshalOptions&#123;</span><br><span class="line"><span class="comment">// Multiline:       false, // 多行显示，Indent</span></span><br><span class="line"><span class="comment">// Indent:          &quot;&quot;,    // 缩进</span></span><br><span class="line"><span class="comment">// AllowPartial:    false,</span></span><br><span class="line">UseProtoNames:   <span class="literal">true</span>, <span class="comment">// 使用原型proto里定义的字段名</span></span><br><span class="line">UseEnumNumbers:  <span class="literal">true</span>, <span class="comment">// 使用枚举enum对应的数字</span></span><br><span class="line">EmitUnpopulated: <span class="literal">true</span>, <span class="comment">// 是否返回空（未填充）的字段</span></span><br><span class="line"><span class="comment">// Resolver:        nil,</span></span><br><span class="line">&#125;,</span><br><span class="line">&#125;,</span><br><span class="line">))</span><br><span class="line"></span><br><span class="line"><span class="comment">// 注册服务</span></span><br><span class="line">err := authpb.RegisterAuthServiceHandlerFromEndpoint(ctx, gwmux, <span class="string">&quot;localhost:8081&quot;</span>, []grpc.DialOption&#123;</span><br><span class="line">grpc.WithBlock(),</span><br><span class="line">grpc.WithTransportCredentials(insecure.NewCredentials()),</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatalln(<span class="string">&quot;注册服务失败&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听http服务</span></span><br><span class="line">err = http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, gwmux)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">log.Fatal(<span class="string">&quot;启动http服务失败:&quot;</span>, err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li>发起http请求<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST \</span><br><span class="line">  &#x27;http://127.0.0.1:8080/v1/auth/login&#x27; \</span><br><span class="line">  --header &#x27;Accept: */*&#x27; \</span><br><span class="line">  --header &#x27;User-Agent: Thunder Client (https://www.thunderclient.com)&#x27; \</span><br><span class="line">  --header &#x27;Content-Type: application/json&#x27; \</span><br><span class="line">  --data-raw &#x27;&#123;</span><br><span class="line">    &quot;code&quot;: &quot;123&quot;</span><br><span class="line">&#125;&#x27;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">返回</span></span><br><span class="line">&#123;</span><br><span class="line">  &quot;accessToken&quot;: &quot;access_token for 123&quot;,</span><br><span class="line">  &quot;expiresIn&quot;: 7200</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><h1 id="gRPC-Gateway代理配置"><a href="#gRPC-Gateway代理配置" class="headerlink" title="gRPC-Gateway代理配置"></a>gRPC-Gateway代理配置</h1><ol><li>注解方式(google.api.http)<br>需要加入依赖文件<a href="https://github.com/googleapis/googleapis">googleapis</a><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">proto</span><br><span class="line">├── google</span><br><span class="line">│   └── api</span><br><span class="line">│       ├── annotations.proto</span><br><span class="line">│       └── http.proto</span><br><span class="line">└── helloworld</span><br><span class="line">    └── hello_world.proto</span><br></pre></td></tr></table></figure>protobuf 文件修改加入注解<figure class="highlight protobuf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">syntax = <span class="string">&quot;proto3&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> helloworld;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;google/api/annotations.proto&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Here is the overall greeting service definition where we define all our endpoints</span></span><br><span class="line"><span class="keyword">service </span><span class="title class_">Greeter</span> &#123;</span><br><span class="line">  <span class="comment">// Sends a greeting</span></span><br><span class="line">  <span class="function"><span class="keyword">rpc</span> SayHello (HelloRequest) <span class="keyword">returns</span> (HelloReply) </span>&#123;</span><br><span class="line">    <span class="keyword">option</span> (google.api.http) = &#123;</span><br><span class="line">      post: <span class="string">&quot;/v1/example/echo&quot;</span></span><br><span class="line">      body: <span class="string">&quot;*&quot;</span></span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// The request message containing the user&#x27;s name</span></span><br><span class="line"><span class="keyword">message </span><span class="title class_">HelloRequest</span> &#123;</span><br><span class="line">  <span class="type">string</span> name = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// The response message containing the greetings</span></span><br><span class="line"><span class="keyword">message </span><span class="title class_">HelloReply</span> &#123;</span><br><span class="line">  <span class="type">string</span> message = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li>yaml配置文件<br>文档地址：<a href="https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/grpc_api_configuration/">https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/grpc_api_configuration/</a><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">type:</span> <span class="string">google.api.Service</span></span><br><span class="line"><span class="attr">config_version:</span> <span class="number">3</span></span><br><span class="line"></span><br><span class="line"><span class="attr">http:</span></span><br><span class="line">  <span class="attr">rules:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">selector:</span> <span class="string">your.service.v1.YourService.Echo</span></span><br><span class="line">      <span class="attr">post:</span> <span class="string">/v1/example/echo</span></span><br><span class="line">      <span class="attr">body:</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;gRPC-Gateway介绍&quot;&gt;&lt;a href=&quot;#gRPC-Gateway介绍&quot; class=&quot;headerlink&quot; title=&quot;gRPC-Gateway介绍&quot;&gt;&lt;/a&gt;gRPC-Gateway介绍&lt;/h1&gt;&lt;h1 id=&quot;gRPC简单实现&quot;&gt;&lt;a href</summary>
      
    
    
    
    <category term="Golang" scheme="https://enoliu.github.io/categories/Golang/"/>
    
    
    <category term="protobuf" scheme="https://enoliu.github.io/tags/protobuf/"/>
    
    <category term="grpc" scheme="https://enoliu.github.io/tags/grpc/"/>
    
    <category term="grpc-gateway" scheme="https://enoliu.github.io/tags/grpc-gateway/"/>
    
  </entry>
  
  <entry>
    <title>golang-protobuf入门记录</title>
    <link href="https://enoliu.github.io/2022/07/15/golang-protobuf%E5%85%A5%E9%97%A8%E8%AE%B0%E5%BD%95/"/>
    <id>https://enoliu.github.io/2022/07/15/golang-protobuf%E5%85%A5%E9%97%A8%E8%AE%B0%E5%BD%95/</id>
    <published>2022-07-15T02:19:25.000Z</published>
    <updated>2022-07-15T07:06:28.081Z</updated>
    
    <content type="html"><![CDATA[<h3 id="语法指南"><a href="#语法指南" class="headerlink" title="语法指南"></a>语法指南</h3><figure class="highlight protobuf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 语法标记，默认为proto2语法</span></span><br><span class="line"><span class="comment">// 必须位于文件开头非空非注释的第一行</span></span><br><span class="line">syntax = <span class="string">&quot;proto3&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以包声明开头，这有助于防止不同项目之间的命名冲突。</span></span><br><span class="line"><span class="keyword">package</span> coolcar;</span><br><span class="line"></span><br><span class="line"><span class="comment">// go_package选项定义了包的导入路径，该路径将包含此文件的所有生成代码。Go 包名称将是导入路径的最后一个路径组件</span></span><br><span class="line"><span class="keyword">option</span> go_package=<span class="string">&quot;coolcar/proto/gen/go/trippb&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 消息体</span></span><br><span class="line"><span class="comment">// 消息体内每个字段都由一个字段类型、字段名称、字段编号组成</span></span><br><span class="line"><span class="comment">// 字段类型：float,int32,int64,uint32,uint64,bool,string,bytes,nested type(复合类型或嵌套类型)</span></span><br><span class="line"><span class="comment">// 字段编号：1~15编号使用一个字节编码，16~2047范围两个编码，因此应该为非常频繁出现的消息元素保留数字 1 到 15</span></span><br><span class="line"><span class="comment">// 数字 19000 到 19999是为 Protocol Buffers 实现保留的，不能使用</span></span><br><span class="line"><span class="comment">// 字段名称：使用小写加下划线，计量字段因带上计量单位，如：duration_sec(时长：秒)，fee_cent(费用：分)</span></span><br><span class="line"><span class="comment">// 保留字段：如果需要更新功能时可以通过 reserved 保留某些字段名称或字段编号，这样就不会被重新使用了，protoc会检查。</span></span><br><span class="line"><span class="keyword">message </span><span class="title class_">Location</span> &#123;</span><br><span class="line">  <span class="type">float</span> latitude = <span class="number">1</span>;</span><br><span class="line">  <span class="type">float</span> longitude = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 枚举</span></span><br><span class="line"><span class="comment">// 必须有一个零值，用于使用0作为默认数字</span></span><br><span class="line"><span class="comment">// 零值必须为第一个元素，以便与proto2语法兼容</span></span><br><span class="line"><span class="comment">// 通过设置 option allow_alias = true; 来为不同的枚举设置同样的值：如SUCCESS</span></span><br><span class="line"><span class="comment">// 常量数字必须在32位整数内，不推荐使用负数（编码低效）</span></span><br><span class="line"><span class="comment">// 枚举可以定义在消息体类，也可以在外面</span></span><br><span class="line"><span class="comment">// 保留字段：如果需要更新功能时可以通过 reserved 保留某些枚举字段或枚举常量，这样就不会被重新使用了，protoc会检查。</span></span><br><span class="line"><span class="keyword">enum </span><span class="title class_">TripStatus</span> &#123;</span><br><span class="line">  <span class="comment">// option allow_alias = true;</span></span><br><span class="line">  TS_NOT_SPECIFIED = <span class="number">0</span>;</span><br><span class="line">  NOT_STARTED = <span class="number">1</span>;</span><br><span class="line">  IN_PROGRESS = <span class="number">2</span>;</span><br><span class="line">  FINISHED = <span class="number">3</span>;</span><br><span class="line">  PAID = <span class="number">4</span>;</span><br><span class="line">  <span class="comment">// SUCCESS = 4;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用其他消息类型</span></span><br><span class="line"><span class="comment">// repeated 用于一个字段保存多个数据</span></span><br><span class="line"><span class="comment">// 关联映射 map&lt;string, Project&gt; projects = 3; map字段不能是repeated</span></span><br><span class="line"><span class="keyword">message </span><span class="title class_">Trip</span> &#123;</span><br><span class="line">  <span class="type">string</span> start = <span class="number">1</span>;</span><br><span class="line">  <span class="type">string</span> end = <span class="number">2</span>;</span><br><span class="line">  Location start_pos = <span class="number">5</span>;</span><br><span class="line">  Location end_pos = <span class="number">6</span>;</span><br><span class="line">  <span class="keyword">repeated</span> Location path_locations = <span class="number">7</span>;</span><br><span class="line">  <span class="type">int32</span> duration_sec = <span class="number">3</span>;</span><br><span class="line">  <span class="type">int32</span> fee_cent = <span class="number">4</span>;</span><br><span class="line">  TripStatus status = <span class="number">8</span>;</span><br><span class="line">  map&lt;<span class="type">string</span>, <span class="type">string</span>&gt; projects = <span class="number">9</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 导入定义</span></span><br><span class="line"><span class="comment">// import &quot;myproject/other_protos.proto&quot;;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">message </span><span class="title class_">GetTripRequest</span> &#123;</span><br><span class="line">  <span class="type">string</span> id = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">message </span><span class="title class_">GetTripResponse</span> &#123;</span><br><span class="line">  <span class="type">string</span> id = <span class="number">1</span>;</span><br><span class="line">  Trip trip = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 定义RPC服务接口</span></span><br><span class="line"><span class="keyword">service </span><span class="title class_">TripService</span> &#123;</span><br><span class="line">  <span class="function"><span class="keyword">rpc</span> GetTrip (GetTripRequest) <span class="keyword">returns</span> (GetTripResponse)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="编译-proto文件"><a href="#编译-proto文件" class="headerlink" title="编译.proto文件"></a>编译.proto文件</h3><ol><li>首先安装protobuf<br>按照系统下载让后安装并加入系统变量<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/protocolbuffers/protobuf/releases</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li>安装protobuf的golang插件<br>编译器插件<code>protoc-gen-go</code>将安装在 中 <code>$GOBIN</code><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">go install google.golang.org/protobuf/cmd/protoc-gen-go@latest</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">grpc服务需要</span></span><br><span class="line">go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest</span><br></pre></td></tr></table></figure></li><li>运行编译器<br><code>$SRC_DIR</code>源码目录，不指定则为当前目录。<code>$DST_DIR</code>输出目录<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">格式</span></span><br><span class="line">protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">demo</span></span><br><span class="line">protoc -I=. --go_out=paths=source_relative:gen/go --go-grpc_out=paths=source_relative:gen/go trip.proto</span><br></pre></td></tr></table></figure></li></ol><h4 id="–go-out参数说明"><a href="#–go-out参数说明" class="headerlink" title="–go_out参数说明"></a>–go_out参数说明</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">--go_out参数用来指定 protoc-gen-go 插件的工作方式和go代码的生成位置</span><br><span class="line"></span><br><span class="line">--go_out主要的两个参数为 plugins 和 paths，分别表示生成go代码所使用的插件和生成的go代码的位置。</span><br><span class="line"></span><br><span class="line">--go_out的写法是参数之间用 逗号 隔开，最后加上 冒号 来指定代码的生成位置。</span><br><span class="line"></span><br><span class="line">比如：--go_out=plugins=grpc,paths=import:.</span><br><span class="line"></span><br><span class="line">paths参数有两个选项，分别是 import 和 source_relative。</span><br><span class="line">默认为 import，表示按照生成的go代码的包的全路径去创建目录层级，</span><br><span class="line">source_relative 表示按照proto源文件的目录层级去创建go代码的目录层级。</span><br><span class="line"></span><br><span class="line">例：</span><br><span class="line"></span><br><span class="line">option go_package=&quot;proto/pb_go&quot;;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">指令1：paths为import，pb文件最终在 pb_go 目录下</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">protoc --proto_path=. --go_out=. proto/greeter/greeter.proto</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">protoc --proto_path=. --go_out=paths=import:. proto/greeter/greeter.proto</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">指令2：paths为source_relative，pb文件最终在 proto/greeter 目录下</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">protoc --proto_path=. --go_out=paths=source_relative:. proto/greeter/greeter.proto</span> </span><br><span class="line"></span><br><span class="line">plugins参数带grpc时会生成一些跟gRPC相关的代码，实现gRPC通信。</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;语法指南&quot;&gt;&lt;a href=&quot;#语法指南&quot; class=&quot;headerlink&quot; title=&quot;语法指南&quot;&gt;&lt;/a&gt;语法指南&lt;/h3&gt;&lt;figure class=&quot;highlight protobuf&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;</summary>
      
    
    
    
    <category term="Golang" scheme="https://enoliu.github.io/categories/Golang/"/>
    
    
    <category term="protobuf" scheme="https://enoliu.github.io/tags/protobuf/"/>
    
    <category term="grpc" scheme="https://enoliu.github.io/tags/grpc/"/>
    
  </entry>
  
  <entry>
    <title>[Hyperf]JWT认证与自动刷新token</title>
    <link href="https://enoliu.github.io/2022/07/07/[hyperf]jwt%E8%AE%A4%E8%AF%81%E4%B8%8E%E8%87%AA%E5%8A%A8%E5%88%B7%E6%96%B0token/"/>
    <id>https://enoliu.github.io/2022/07/07/[hyperf]jwt%E8%AE%A4%E8%AF%81%E4%B8%8E%E8%87%AA%E5%8A%A8%E5%88%B7%E6%96%B0token/</id>
    <published>2022-07-07T02:19:25.000Z</published>
    <updated>2022-07-07T02:45:40.807Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Auth组件"><a href="#Auth组件" class="headerlink" title="Auth组件"></a>Auth组件</h2><ol><li>安装<a href="https://github.com/hyperf-ext/auth" title="hyperf-ext/auth">hyperf-ext&#x2F;auth</a>组件<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">composer <span class="keyword">require</span> hyperf-ext/auth</span><br></pre></td></tr></table></figure></li><li>发布配置文件（文件位于 config&#x2F;autoload&#x2F;auth.php）<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php vendor:publish hyperf-ext/auth</span><br></pre></td></tr></table></figure></li><li>添加助手方法文件app&#x2F;Functions.php<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (! <span class="title function_ invoke__">function_exists</span>(<span class="string">&#x27;auth&#x27;</span>)) &#123;</span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * Auth认证辅助方法</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> string|null $guard 守护名称</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> \HyperfExt\Auth\Contracts\GuardInterface|\HyperfExt\Auth\Contracts\StatefulGuardInterface|\HyperfExt\Auth\Contracts\StatelessGuardInterface</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">auth</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$guard</span> = <span class="string">&#x27;api&#x27;</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_ invoke__">is_null</span>(<span class="variable">$guard</span>)) <span class="variable">$guard</span> = <span class="title function_ invoke__">config</span>(<span class="string">&#x27;auth.default.guard&#x27;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_ invoke__">make</span>(<span class="title class_">\HyperfExt\Auth\Contracts\AuthManagerInterface</span>::<span class="variable language_">class</span>)-&gt;<span class="title function_ invoke__">guard</span>(<span class="variable">$guard</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>加完后记得要用composer自动加载哟<br><img src="/../assets/20220707/fXvZX5Hm7v.png"></li></ol><h2 id="Auth依赖组件"><a href="#Auth依赖组件" class="headerlink" title="Auth依赖组件"></a>Auth依赖组件</h2><ol><li>安装<a href="https://github.com/hyperf-ext/hashing" title="hyperf-ext/hashing">hyperf-ext&#x2F;hashing</a><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">composer <span class="keyword">require</span> hyperf-ext/hashing</span><br></pre></td></tr></table></figure></li><li>发布配置（配置文件位于 config&#x2F;autoload&#x2F;hashing.php）<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php vendor:publish hyperf-ext/hashing</span><br></pre></td></tr></table></figure></li></ol><h2 id="JWT组件"><a href="#JWT组件" class="headerlink" title="JWT组件"></a>JWT组件</h2><ol><li>安装<a href="https://github.com/hyperf-ext/jwt" title="hyperf-ext/jwt">hyperf-ext&#x2F;jwt</a><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">composer <span class="keyword">require</span> hyperf-ext/jwt</span><br></pre></td></tr></table></figure></li><li>发布配置文件（文件位于 config&#x2F;autoload&#x2F;jwt.php）<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php vendor:publish hyperf-ext/jwt</span><br></pre></td></tr></table></figure></li></ol><h2 id="创建两个数据库迁移文件"><a href="#创建两个数据库迁移文件" class="headerlink" title="创建两个数据库迁移文件"></a>创建两个数据库迁移文件</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php gen:migration create_users_table</span><br><span class="line">php bin/hyperf.php gen:migration create_administrators_table</span><br></pre></td></tr></table></figure><p>两个表内容其实是一样的，用来模拟多守护认证。如下（根据实际需求调整）</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Database</span>\<span class="title">Schema</span>\<span class="title">Schema</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Database</span>\<span class="title">Schema</span>\<span class="title">Blueprint</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Database</span>\<span class="title">Migrations</span>\<span class="title">Migration</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CreateUsersTable</span> <span class="keyword">extends</span> <span class="title">Migration</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Run the migrations.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">up</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="title class_">Schema</span>::<span class="title function_ invoke__">create</span>(<span class="string">&#x27;users&#x27;</span>, function (Blueprint <span class="variable">$table</span>) &#123;</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="title function_ invoke__">bigIncrements</span>(<span class="string">&#x27;id&#x27;</span>);</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="title function_ invoke__">char</span>(<span class="string">&#x27;username&#x27;</span>, <span class="number">20</span>)-&gt;<span class="keyword">default</span>(<span class="string">&#x27;&#x27;</span>)-&gt;<span class="title function_ invoke__">comment</span>(<span class="string">&#x27;用户昵称&#x27;</span>);</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="title function_ invoke__">char</span>(<span class="string">&#x27;password&#x27;</span>, <span class="number">200</span>)-&gt;<span class="keyword">default</span>(<span class="string">&#x27;&#x27;</span>)-&gt;<span class="title function_ invoke__">comment</span>(<span class="string">&#x27;用户密码&#x27;</span>);</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="keyword">string</span>(<span class="string">&#x27;avatar&#x27;</span>)-&gt;<span class="keyword">default</span>(<span class="string">&#x27;&#x27;</span>)-&gt;<span class="title function_ invoke__">comment</span>(<span class="string">&#x27;用户头像&#x27;</span>);</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="title function_ invoke__">char</span>(<span class="string">&#x27;email&#x27;</span>, <span class="number">50</span>)-&gt;<span class="keyword">default</span>(<span class="string">&#x27;&#x27;</span>)-&gt;<span class="title function_ invoke__">unique</span>(<span class="string">&#x27;email&#x27;</span>)-&gt;<span class="title function_ invoke__">comment</span>(<span class="string">&#x27;用户邮箱&#x27;</span>);</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="title function_ invoke__">char</span>(<span class="string">&#x27;phone&#x27;</span>, <span class="number">15</span>)-&gt;<span class="keyword">default</span>(<span class="string">&#x27;&#x27;</span>)-&gt;<span class="title function_ invoke__">unique</span>(<span class="string">&#x27;phone&#x27;</span>)-&gt;<span class="title function_ invoke__">comment</span>(<span class="string">&#x27;用户手机号&#x27;</span>);</span><br><span class="line">            <span class="variable">$table</span>-&gt;<span class="title function_ invoke__">timestamps</span>();</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Reverse the migrations.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">down</span>(<span class="params"></span>): <span class="title">void</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="title class_">Schema</span>::<span class="title function_ invoke__">dropIfExists</span>(<span class="string">&#x27;users&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="JWT配置"><a href="#JWT配置" class="headerlink" title="JWT配置"></a>JWT配置</h2><ol><li>生成jwt key<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php gen:jwt-secret</span><br></pre></td></tr></table></figure></li><li>可选（Set the JWT private key and public key used to sign the tokens）<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php gen:jwt-keypair</span><br></pre></td></tr></table></figure></li><li>.env文件<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">JWT_BLACKLIST_GRACE_PERIOD=<span class="number">5</span>  设置宽限期（以秒为单位）以防止并发请求失败。</span><br><span class="line">JWT_TTL=<span class="number">3600</span> 指定令牌有效的时长（以秒为单位）。默认为 <span class="number">1</span> 小时</span><br></pre></td></tr></table></figure>4.其他配置基本可以不变(config&#x2F;autoload&#x2F;jwt.php)</li></ol><h2 id="添加Auth守护guard"><a href="#添加Auth守护guard" class="headerlink" title="添加Auth守护guard"></a>添加Auth守护guard</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">declare</span>(strict_types=<span class="number">1</span>);</span><br><span class="line"><span class="keyword">return</span> [</span><br><span class="line">    <span class="string">&#x27;default&#x27;</span> =&gt; [</span><br><span class="line">        <span class="string">&#x27;guard&#x27;</span> =&gt; <span class="string">&#x27;api&#x27;</span>,<span class="comment">// 默认接口api守护</span></span><br><span class="line">        <span class="string">&#x27;passwords&#x27;</span> =&gt; <span class="string">&#x27;users&#x27;</span>,</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;guards&#x27;</span> =&gt; [</span><br><span class="line">        <span class="string">&#x27;web&#x27;</span> =&gt; [</span><br><span class="line">            <span class="string">&#x27;driver&#x27;</span> =&gt; <span class="title class_">\HyperfExt\Auth\Guards\SessionGuard</span>::<span class="variable language_">class</span>,</span><br><span class="line">            <span class="string">&#x27;provider&#x27;</span> =&gt; <span class="string">&#x27;users&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;options&#x27;</span> =&gt; [],</span><br><span class="line">        ],</span><br><span class="line"><span class="comment">// 接口api守护</span></span><br><span class="line">        <span class="string">&#x27;api&#x27;</span> =&gt; [</span><br><span class="line">            <span class="string">&#x27;driver&#x27;</span> =&gt; <span class="title class_">\HyperfExt\Auth\Guards\JwtGuard</span>::<span class="variable language_">class</span>,</span><br><span class="line">            <span class="string">&#x27;provider&#x27;</span> =&gt; <span class="string">&#x27;api&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;options&#x27;</span> =&gt; [],</span><br><span class="line">        ],</span><br><span class="line"><span class="comment">// 管理端admin守护</span></span><br><span class="line">        <span class="string">&#x27;admin&#x27;</span> =&gt; [</span><br><span class="line">            <span class="string">&#x27;driver&#x27;</span> =&gt; <span class="title class_">\HyperfExt\Auth\Guards\JwtGuard</span>::<span class="variable language_">class</span>,</span><br><span class="line">            <span class="string">&#x27;provider&#x27;</span> =&gt; <span class="string">&#x27;admin&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;options&#x27;</span> =&gt; [],</span><br><span class="line">        ],</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;providers&#x27;</span> =&gt; [</span><br><span class="line">        <span class="string">&#x27;api&#x27;</span> =&gt; [</span><br><span class="line">            <span class="string">&#x27;driver&#x27;</span> =&gt; <span class="title class_">\HyperfExt\Auth\UserProviders\ModelUserProvider</span>::<span class="variable language_">class</span>,</span><br><span class="line">            <span class="string">&#x27;options&#x27;</span> =&gt; [</span><br><span class="line">                <span class="string">&#x27;model&#x27;</span> =&gt; <span class="title class_">\App\Model\User</span>::<span class="variable language_">class</span>,<span class="comment">// 用户模型</span></span><br><span class="line">                <span class="string">&#x27;hash_driver&#x27;</span> =&gt; <span class="string">&#x27;bcrypt&#x27;</span>,</span><br><span class="line">            ],</span><br><span class="line">        ],</span><br><span class="line"></span><br><span class="line">        <span class="string">&#x27;admin&#x27;</span> =&gt; [</span><br><span class="line">            <span class="string">&#x27;driver&#x27;</span> =&gt; <span class="title class_">\HyperfExt\Auth\UserProviders\ModelUserProvider</span>::<span class="variable language_">class</span>,</span><br><span class="line">            <span class="string">&#x27;options&#x27;</span> =&gt; [</span><br><span class="line">                <span class="string">&#x27;model&#x27;</span> =&gt; <span class="title class_">\App\Model\Admin</span>::<span class="variable language_">class</span>,<span class="comment">// 管理员模型</span></span><br><span class="line">                <span class="string">&#x27;hash_driver&#x27;</span> =&gt; <span class="string">&#x27;bcrypt&#x27;</span>,</span><br><span class="line">            ],</span><br><span class="line">        ]</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;passwords&#x27;</span> =&gt; [</span><br><span class="line">        <span class="string">&#x27;users&#x27;</span> =&gt; [</span><br><span class="line">            <span class="string">&#x27;driver&#x27;</span> =&gt; <span class="title class_">\HyperfExt\Auth\Passwords\DatabaseTokenRepository</span>::<span class="variable language_">class</span>,</span><br><span class="line">            <span class="string">&#x27;provider&#x27;</span> =&gt; <span class="string">&#x27;users&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;options&#x27;</span> =&gt; [</span><br><span class="line">                <span class="string">&#x27;connection&#x27;</span> =&gt; <span class="literal">null</span>,</span><br><span class="line">                <span class="string">&#x27;table&#x27;</span> =&gt; <span class="string">&#x27;password_resets&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;expire&#x27;</span> =&gt; <span class="number">3600</span>,</span><br><span class="line">                <span class="string">&#x27;throttle&#x27;</span> =&gt; <span class="number">60</span>,</span><br><span class="line">                <span class="string">&#x27;hash_driver&#x27;</span> =&gt; <span class="literal">null</span>,</span><br><span class="line">            ],</span><br><span class="line">        ],</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;password_timeout&#x27;</span> =&gt; <span class="number">10800</span>,</span><br><span class="line">    <span class="string">&#x27;policies&#x27;</span> =&gt; [</span><br><span class="line">        <span class="comment">//Model::class =&gt; Policy::class,</span></span><br><span class="line">    ],</span><br><span class="line">];</span><br></pre></td></tr></table></figure><h2 id="更新模型"><a href="#更新模型" class="headerlink" title="更新模型"></a>更新模型</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">declare</span> (strict_types=<span class="number">1</span>);</span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">App</span>\<span class="title class_">Model</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">ModelCache</span>\<span class="title">Cacheable</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Auth</span>\<span class="title">Authenticatable</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Auth</span>\<span class="title">Contracts</span>\<span class="title">AuthenticatableInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Jwt</span>\<span class="title">Contracts</span>\<span class="title">JwtSubjectInterface</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> <span class="keyword">extends</span> <span class="title">Model</span> <span class="keyword">implements</span> <span class="title">AuthenticatableInterface</span> ,<span class="title">JwtSubjectInterface</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">use</span> <span class="title">Authenticatable</span>, <span class="title">Cacheable</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The table associated with the model.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@var</span> string</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$table</span> = <span class="string">&#x27;users&#x27;</span>;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The attributes that are mass assignable.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@var</span> array</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$fillable</span> = [];</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The attributes that should be cast to native types.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@var</span> array</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$casts</span> = [];</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getJwtIdentifier</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">getKey</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * JWT自定义载荷</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> array</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">getJwtCustomClaims</span>(<span class="params"></span>): <span class="title">array</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> [</span><br><span class="line">            <span class="string">&#x27;guard&#x27;</span> =&gt; <span class="string">&#x27;api&#x27;</span>    <span class="comment">// 添加一个自定义载荷保存守护名称，方便后续判断</span></span><br><span class="line">        ];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>创建AuthController</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php gen:controller AuthController</span><br></pre></td></tr></table></figure><p>内容如下</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">declare</span>(strict_types=<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">App</span>\<span class="title class_">Controller</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Constants</span>\<span class="title">HttpCode</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Traits</span>\<span class="title">ApiResponseTrait</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">HttpServer</span>\<span class="title">Annotation</span>\<span class="title">Controller</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">HttpServer</span>\<span class="title">Annotation</span>\<span class="title">Middleware</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">HttpServer</span>\<span class="title">Annotation</span>\<span class="title">Middlewares</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">HttpServer</span>\<span class="title">Annotation</span>\<span class="title">RequestMapping</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">HttpServer</span>\<span class="title">Contract</span>\<span class="title">RequestInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Middleware</span>\<span class="title">Auth</span>\<span class="title">RefreshTokenMiddleware</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Jwt</span>\<span class="title">Contracts</span>\<span class="title">JwtFactoryInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Http</span>\<span class="title">Message</span>\<span class="title">ResponseInterface</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Controller</span>(prefix=&quot;auth&quot;)</span></span><br><span class="line"><span class="comment"> * Class AuthController</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@package</span> App\Controller</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AuthController</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">use</span> <span class="title">ApiResponseTrait</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@RequestMapping</span>(path=&quot;login&quot;, methods=&#123;&quot;POST&quot;&#125;)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> RequestInterface $request</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ResponseInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">login</span>(<span class="params">RequestInterface <span class="variable">$request</span></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable">$credentials</span> = <span class="variable">$request</span>-&gt;<span class="title function_ invoke__">inputs</span>([<span class="string">&#x27;email&#x27;</span>, <span class="string">&#x27;password&#x27;</span>]);</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable">$token</span> = <span class="title function_ invoke__">auth</span>(<span class="string">&#x27;api&#x27;</span>)-&gt;<span class="title function_ invoke__">attempt</span>(<span class="variable">$credentials</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">setHttpCode</span>(<span class="title class_">HttpCode</span>::<span class="variable constant_">UNAUTHORIZED</span>)-&gt;<span class="title function_ invoke__">fail</span>(<span class="string">&#x27;Unauthorized&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">respondWithToken</span>(<span class="variable">$token</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@RequestMapping</span>(path=&quot;user&quot;)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@Middlewares</span>(&#123;<span class="doctag">@Middleware</span>(RefreshTokenMiddleware::class)&#125;)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">me</span>(<span class="params"></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">success</span>(<span class="title function_ invoke__">auth</span>(<span class="string">&#x27;api&#x27;</span>)-&gt;<span class="title function_ invoke__">user</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@RequestMapping</span>(path=&quot;refresh&quot;, methods=&#123;&quot;GET&quot;&#125;)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">refresh</span>(<span class="params"></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">respondWithToken</span>(<span class="title function_ invoke__">auth</span>(<span class="string">&#x27;api&#x27;</span>)-&gt;<span class="title function_ invoke__">refresh</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@RequestMapping</span>(path=&quot;logout&quot;, methods=&#123;&quot;DELETE&quot;&#125;)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">logout</span>(<span class="params"></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="title function_ invoke__">auth</span>(<span class="string">&#x27;api&#x27;</span>)-&gt;<span class="title function_ invoke__">logout</span>();</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">success</span>([<span class="string">&#x27;message&#x27;</span> =&gt; <span class="string">&#x27;Successfully logged out&#x27;</span>]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $token</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ResponseInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">respondWithToken</span>(<span class="params"><span class="variable">$token</span></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">success</span>([</span><br><span class="line">            <span class="string">&#x27;access_token&#x27;</span> =&gt; <span class="variable">$token</span>,</span><br><span class="line">            <span class="string">&#x27;token_type&#x27;</span> =&gt; <span class="string">&#x27;bearer&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;expire_in&#x27;</span> =&gt; <span class="title function_ invoke__">make</span>(<span class="title class_">JwtFactoryInterface</span>::<span class="variable language_">class</span>)-&gt;<span class="title function_ invoke__">make</span>()-&gt;<span class="title function_ invoke__">getPayloadFactory</span>()-&gt;<span class="title function_ invoke__">getTtl</span>()</span><br><span class="line">        ]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="自动刷新token中间件"><a href="#自动刷新token中间件" class="headerlink" title="自动刷新token中间件"></a>自动刷新token中间件</h2><p>生成中间件RefreshTokenMiddleware</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php bin/hyperf.php gen:middleware Auth\\RefreshTokenMiddleware</span><br></pre></td></tr></table></figure><p>内容如下</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">declare</span>(strict_types=<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">App</span>\<span class="title class_">Middleware</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Constants</span>\<span class="title">HttpCode</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Utils</span>\<span class="title">ApiResponseTrait</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Exception</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Di</span>\<span class="title">Annotation</span>\<span class="title">Inject</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Jwt</span>\<span class="title">Contracts</span>\<span class="title">ManagerInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Jwt</span>\<span class="title">Exceptions</span>\<span class="title">TokenExpiredException</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">HyperfExt</span>\<span class="title">Jwt</span>\<span class="title">JwtFactory</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Container</span>\<span class="title">ContainerInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Http</span>\<span class="title">Message</span>\<span class="title">ResponseInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Http</span>\<span class="title">Server</span>\<span class="title">MiddlewareInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Http</span>\<span class="title">Message</span>\<span class="title">ServerRequestInterface</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Http</span>\<span class="title">Server</span>\<span class="title">RequestHandlerInterface</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RefreshTokenMiddleware</span> <span class="keyword">implements</span> <span class="title">MiddlewareInterface</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">use</span> <span class="title">ApiResponseTrait</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@var</span> ContainerInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$container</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@Inject</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@var</span> ManagerInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$manager</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@Inject</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@var</span> JwtFactory</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$jwtFactory</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params">ContainerInterface <span class="variable">$container</span></span>)</span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;container = <span class="variable">$container</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">process</span>(<span class="params">ServerRequestInterface <span class="variable">$request</span>, RequestHandlerInterface <span class="variable">$handler</span></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable">$jwt</span> = <span class="variable language_">$this</span>-&gt;jwtFactory-&gt;<span class="title function_ invoke__">make</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="variable">$jwt</span>-&gt;<span class="title function_ invoke__">checkOrFail</span>();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (<span class="built_in">Exception</span> <span class="variable">$exception</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (! <span class="variable">$exception</span> <span class="keyword">instanceof</span> TokenExpiredException) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">setHttpCode</span>(<span class="title class_">HttpCode</span>::<span class="variable constant_">UNPROCESSABLE_ENTITY</span>)-&gt;<span class="title function_ invoke__">fail</span>(<span class="variable">$exception</span>-&gt;<span class="title function_ invoke__">getMessage</span>());</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="variable">$token</span> = <span class="variable">$jwt</span>-&gt;<span class="title function_ invoke__">getToken</span>();</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 刷新token</span></span><br><span class="line">                <span class="variable">$new_token</span> = <span class="variable">$jwt</span>-&gt;<span class="title function_ invoke__">getManager</span>()-&gt;<span class="title function_ invoke__">refresh</span>(<span class="variable">$token</span>);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 解析token载荷信息</span></span><br><span class="line">                <span class="variable">$payload</span> = <span class="variable">$jwt</span>-&gt;<span class="title function_ invoke__">getManager</span>()-&gt;<span class="title function_ invoke__">decode</span>(<span class="variable">$token</span>, <span class="literal">false</span>, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 旧token加入黑名单</span></span><br><span class="line">                <span class="variable">$jwt</span>-&gt;<span class="title function_ invoke__">getManager</span>()-&gt;<span class="title function_ invoke__">getBlacklist</span>()-&gt;<span class="title function_ invoke__">add</span>(<span class="variable">$payload</span>);</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 一次性登录，保证此次请求畅通</span></span><br><span class="line">                <span class="title function_ invoke__">auth</span>(<span class="variable">$payload</span>-&gt;<span class="title function_ invoke__">get</span>(<span class="string">&#x27;guard&#x27;</span>) ?? <span class="title function_ invoke__">config</span>(<span class="string">&#x27;auth.default.guard&#x27;</span>))-&gt;<span class="title function_ invoke__">onceUsingId</span>(<span class="variable">$payload</span>-&gt;<span class="title function_ invoke__">get</span>(<span class="string">&#x27;sub&#x27;</span>));</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> <span class="variable">$handler</span>-&gt;<span class="title function_ invoke__">handle</span>(<span class="variable">$request</span>)-&gt;<span class="title function_ invoke__">withHeader</span>(<span class="string">&#x27;authorization&#x27;</span>, <span class="string">&#x27;bearer &#x27;</span> . <span class="variable">$new_token</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (<span class="built_in">Exception</span> <span class="variable">$exception</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">setHttpCode</span>(<span class="title class_">HttpCode</span>::<span class="variable constant_">UNPROCESSABLE_ENTITY</span>)-&gt;<span class="title function_ invoke__">fail</span>(<span class="variable">$exception</span>-&gt;<span class="title function_ invoke__">getMessage</span>());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable">$handler</span>-&gt;<span class="title function_ invoke__">handle</span>(<span class="variable">$request</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="补充-ApiResponseTrait"><a href="#补充-ApiResponseTrait" class="headerlink" title="补充 ApiResponseTrait"></a>补充 ApiResponseTrait</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">App</span>\<span class="title class_">Traits</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Constants</span>\<span class="title">HttpCode</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">HttpMessage</span>\<span class="title">Stream</span>\<span class="title">SwooleStream</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Utils</span>\<span class="title">Codec</span>\<span class="title">Json</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Utils</span>\<span class="title">Context</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Utils</span>\<span class="title">Contracts</span>\<span class="title">Arrayable</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hyperf</span>\<span class="title">Utils</span>\<span class="title">Contracts</span>\<span class="title">Jsonable</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Psr</span>\<span class="title">Http</span>\<span class="title">Message</span>\<span class="title">ResponseInterface</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">trait</span> <span class="title">ApiResponseTrait</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$httpCode</span> = <span class="title class_">HttpCode</span>::<span class="variable constant_">OK</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$headers</span> = [</span><br><span class="line">        <span class="string">&#x27;Author&#x27;</span> =&gt; <span class="string">&#x27;Colorado&#x27;</span></span><br><span class="line">    ];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$errorCode</span> = <span class="number">100000</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="variable">$errorMsg</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> <span class="variable">$response</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 成功响应</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mixed $data</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ResponseInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">success</span>(<span class="params"><span class="variable">$data</span></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">respond</span>(<span class="variable">$data</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 错误返回</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> string $err_msg     错误信息</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> int    $err_code    错误业务码</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> array  $data        额外返回的数据</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ResponseInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">fail</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$err_msg</span> = <span class="string">&#x27;&#x27;</span>, <span class="keyword">int</span> <span class="variable">$err_code</span> = <span class="number">200000</span>, <span class="keyword">array</span> <span class="variable">$data</span> = []</span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">setHttpCode</span>(<span class="variable">$this</span>-&gt;httpCode == <span class="title class_">HttpCode</span>::<span class="variable constant_">OK</span> ? <span class="title class_">HttpCode</span>::<span class="variable constant_">BAD_REQUEST</span> : <span class="variable">$this</span>-&gt;httpCode)</span><br><span class="line">            -&gt;<span class="title function_ invoke__">respond</span>([</span><br><span class="line">                <span class="string">&#x27;err_code&#x27;</span> =&gt; <span class="variable">$err_code</span> ?? <span class="variable">$this</span>-&gt;errorCode,</span><br><span class="line">                <span class="string">&#x27;err_msg&#x27;</span> =&gt; <span class="variable">$err_msg</span> ?? <span class="variable">$this</span>-&gt;errorMsg,</span><br><span class="line">                <span class="string">&#x27;data&#x27;</span> =&gt; <span class="variable">$data</span></span><br><span class="line">            ]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置http返回码</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> int $code    http返回码</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> $this</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">setHttpCode</span>(<span class="params"><span class="keyword">int</span> <span class="variable">$code</span> = <span class="title class_">HttpCode</span>::<span class="variable constant_">OK</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;httpCode = <span class="variable">$code</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置返回头部header值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> string $key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>        $value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> $this</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">addHttpHeader</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$key</span>, <span class="variable">$value</span></span>): <span class="title">self</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;headers += [<span class="variable">$key</span> =&gt; <span class="variable">$value</span>];</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 批量设置头部返回</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> array $headers    header数组：[key1 =&gt; value1, key2 =&gt; value2]</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> $this</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">addHttpHeaders</span>(<span class="params"><span class="keyword">array</span> <span class="variable">$headers</span> = []</span>): <span class="title">self</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable language_">$this</span>-&gt;headers += <span class="variable">$headers</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> null|array|Arrayable|Jsonable|string $response</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ResponseInterface</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">respond</span>(<span class="params"><span class="variable">$response</span></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_ invoke__">is_string</span>(<span class="variable">$response</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">response</span>()-&gt;<span class="title function_ invoke__">withAddedHeader</span>(<span class="string">&#x27;content-type&#x27;</span>, <span class="string">&#x27;text/plain&#x27;</span>)-&gt;<span class="title function_ invoke__">withBody</span>(<span class="keyword">new</span> <span class="title class_">SwooleStream</span>(<span class="variable">$response</span>));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_ invoke__">is_array</span>(<span class="variable">$response</span>) || <span class="variable">$response</span> <span class="keyword">instanceof</span> Arrayable) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">response</span>()</span><br><span class="line">                -&gt;<span class="title function_ invoke__">withAddedHeader</span>(<span class="string">&#x27;content-type&#x27;</span>, <span class="string">&#x27;application/json&#x27;</span>)</span><br><span class="line">                -&gt;<span class="title function_ invoke__">withBody</span>(<span class="keyword">new</span> <span class="title class_">SwooleStream</span>(<span class="title class_">Json</span>::<span class="title function_ invoke__">encode</span>(<span class="variable">$response</span>)));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="variable">$response</span> <span class="keyword">instanceof</span> Jsonable) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">response</span>()</span><br><span class="line">                -&gt;<span class="title function_ invoke__">withAddedHeader</span>(<span class="string">&#x27;content-type&#x27;</span>, <span class="string">&#x27;application/json&#x27;</span>)</span><br><span class="line">                -&gt;<span class="title function_ invoke__">withBody</span>(<span class="keyword">new</span> <span class="title class_">SwooleStream</span>((<span class="keyword">string</span>)<span class="variable">$response</span>));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">$this</span>-&gt;<span class="title function_ invoke__">response</span>()-&gt;<span class="title function_ invoke__">withAddedHeader</span>(<span class="string">&#x27;content-type&#x27;</span>, <span class="string">&#x27;text/plain&#x27;</span>)-&gt;<span class="title function_ invoke__">withBody</span>(<span class="keyword">new</span> <span class="title class_">SwooleStream</span>((<span class="keyword">string</span>)<span class="variable">$response</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> mixed|ResponseInterface|null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="function"><span class="keyword">function</span> <span class="title">response</span>(<span class="params"></span>): <span class="title">ResponseInterface</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="variable">$response</span> = <span class="title class_">Context</span>::<span class="title function_ invoke__">get</span>(<span class="title class_">ResponseInterface</span>::<span class="variable language_">class</span>);</span><br><span class="line">        <span class="keyword">foreach</span> (<span class="variable language_">$this</span>-&gt;headers <span class="keyword">as</span> <span class="variable">$key</span> =&gt; <span class="variable">$value</span>) &#123;</span><br><span class="line">            <span class="variable">$response</span> = <span class="variable">$response</span>-&gt;<span class="title function_ invoke__">withHeader</span>(<span class="variable">$key</span>, <span class="variable">$value</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable">$response</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="hyperf新人，老手勿喷，共同研究，一起进步"><a href="#hyperf新人，老手勿喷，共同研究，一起进步" class="headerlink" title="hyperf新人，老手勿喷，共同研究，一起进步"></a>hyperf新人，老手勿喷，共同研究，一起进步</h2>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Auth组件&quot;&gt;&lt;a href=&quot;#Auth组件&quot; class=&quot;headerlink&quot; title=&quot;Auth组件&quot;&gt;&lt;/a&gt;Auth组件&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;安装&lt;a href=&quot;https://github.com/hyperf-ext/auth&quot; t</summary>
      
    
    
    
    <category term="PHP" scheme="https://enoliu.github.io/categories/PHP/"/>
    
    
    <category term="hyperf" scheme="https://enoliu.github.io/tags/hyperf/"/>
    
    <category term="jwt" scheme="https://enoliu.github.io/tags/jwt/"/>
    
    <category term="php" scheme="https://enoliu.github.io/tags/php/"/>
    
  </entry>
  
</feed>
