渝之涯 發表於 2020-7-17 10:47:00

Vue+node.js 实现 jwt token验证

<p>项目架构:vue+node.js</p>
<p>jwt 验证流程</p>
<p>1、客户端访问登陆接口(不带token),请求服务器验证</p>
<p>2、服务器验证通过,通过jwt返回给客户端一个token</p>
<p>3、客户端请求其他接口时带上从服务器获取的token</p>
<p>4、服务器验证客户端的token,验证通过后,返回给客户端访问接口数据</p>
<p>阮一峰 JSON Web Token:</p>
<p>http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html</p>
<p>&nbsp;</p>
<p><strong>服务端node.js</strong></p>
<p>1、安装依赖</p>
<p><span style="color: rgba(136, 136, 136, 1)">  npm install jsonwebtoken &nbsp;–save</span></p>
<p><span style="color: rgba(136, 136, 136, 1)">  npm install koa-jwt –save</span></p>
<p>2、中间件请求token</p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">app.use(async&nbsp;(ctx,&nbsp;next)&nbsp;=&gt;&nbsp;{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;let&nbsp;token&nbsp;=&nbsp;ctx.header.authorization;</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;next().catch((err)&nbsp;=&gt;&nbsp;{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(err.status&nbsp;===&nbsp;404)&nbsp;{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.status&nbsp;=&nbsp;404;</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.body&nbsp;=&nbsp;{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code:&nbsp;404,</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msg:&nbsp;err.message</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;err;</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;})</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">});</span></p>
<p>&nbsp;</p>
<p>3、排除不验证的请求</p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">app.use(koajwt({&nbsp;secret:&nbsp;secret&nbsp;}).unless({</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;登录接口不需要验证</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;path:&nbsp;[/^\/api\/login/]</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">}));</span></p>
<p>&nbsp;</p>
<p>4、登陆签发token</p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">app.use(async&nbsp;(ctx,&nbsp;next)&nbsp;=&gt;&nbsp;{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(ctx.request.method==='POST'&amp;&amp;ctx.request.url==='/api/login'){</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;postData&nbsp;=&nbsp;ctx.request.body.user</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;{login_name,login_password}=JSON.parse(postData)</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; //判断账号和密码是否正确</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">    //xxx</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">    //登陆成功返回token</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; const&nbsp;token=sign({login_name},secret,{expiresIn:'1h'})&nbsp;</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; ctx.body=token</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//继续执行api请求</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;await&nbsp;next()</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p align="left"><span style="color: rgba(136, 136, 136, 1)">});</span></p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_7dd5b6aa-fe98-43d7-8cf8-5bc75d323ef2" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_7dd5b6aa-fe98-43d7-8cf8-5bc75d323ef2" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_7dd5b6aa-fe98-43d7-8cf8-5bc75d323ef2" class="cnblogs_code_hide">
<pre>

<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">

* @Author: wuyongxian

* @Date: 2019-11-04 17:52:58

* @Last Modified by:

* @Last Modified time: 2019-11-04 17:53:23

</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

const Koa </span>= require('koa'<span style="color: rgba(0, 0, 0, 1)">);

const app </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Koa();

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">jwt token验证</span>
<span style="color: rgba(0, 0, 0, 1)">
const { sign } </span>= require('jsonwebtoken'<span style="color: rgba(0, 0, 0, 1)">);

const secret </span>= 'xxx'<span style="color: rgba(0, 0, 0, 1)">;

const koajwt </span>= require('koa-jwt'<span style="color: rgba(0, 0, 0, 1)">);



</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 中间件对token进行验证</span>
<span style="color: rgba(0, 0, 0, 1)">
app.use(async (ctx, next) </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> let token = ctx.header.authorization;</span>

    <span style="color: rgba(0, 0, 255, 1)">return</span> next().<span style="color: rgba(0, 0, 255, 1)">catch</span>((err) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (err.status === 404<span style="color: rgba(0, 0, 0, 1)">) {

            ctx.status </span>= 404<span style="color: rgba(0, 0, 0, 1)">;

            ctx.body </span>=<span style="color: rgba(0, 0, 0, 1)"> {

                code: </span>404<span style="color: rgba(0, 0, 0, 1)">,

                msg: err.message

            }

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

            </span><span style="color: rgba(0, 0, 255, 1)">throw</span><span style="color: rgba(0, 0, 0, 1)"> err;

      }

    })

});

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">排除不验证的请求</span>
<span style="color: rgba(0, 0, 0, 1)">
app.use(koajwt({ secret: secret }).unless({

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 登录接口不需要验证</span>
<span style="color: rgba(0, 0, 0, 1)">
    path: [</span>/^\/api\/login/<span style="color: rgba(0, 0, 0, 1)">]

}));



app.use(async (ctx, next) </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {

   </span><span style="color: rgba(0, 0, 255, 1)">if</span>(ctx.request.method==='POST'&amp;&amp;ctx.request.url==='/api/login'<span style="color: rgba(0, 0, 0, 1)">){

            const postData </span>=<span style="color: rgba(0, 0, 0, 1)"> ctx.request.body.user

            const {login_name,login_password}</span>=<span style="color: rgba(0, 0, 0, 1)">JSON.parse(postData)

             </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断账号和密码是否正确</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">xxx</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">登陆成功返回token</span>
<span style="color: rgba(0, 0, 0, 1)">
         const token</span>=sign({login_name},secret,{expiresIn:'1h'<span style="color: rgba(0, 0, 0, 1)">})

            ctx.body</span>=<span style="color: rgba(0, 0, 0, 1)">token

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

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">继续执行api请求</span>
<span style="color: rgba(0, 0, 0, 1)">
            await next()

      }

});



app.listen(</span>3000);</pre>
</div>
<span class="cnblogs_code_collapse">node.js 完整代码</span></div>
<p>参考:https://www.jianshu.com/p/663520bd7e95</p>
<p>&nbsp;</p>
<p><strong>客户端vue:</strong></p>
<p>1、登陆验证获取token</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_f4fed023-d54c-4045-aed8-7f4b18eb310c" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_f4fed023-d54c-4045-aed8-7f4b18eb310c" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_f4fed023-d54c-4045-aed8-7f4b18eb310c" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">   loginAuth() {

                let params </span>=<span style="color: rgba(0, 0, 0, 1)"> {

                  login_name: </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ruleForm.username,

                  login_password: md5(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.ruleForm.password)

                }

                let that </span>= <span style="color: rgba(0, 0, 255, 1)">this</span>

                  <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">axios 请求后台接口</span>
<span style="color: rgba(0, 0, 0, 1)">
                api.login(params).then(res </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {

                  </span><span style="color: rgba(0, 0, 255, 1)">if</span> (res.code == 0<span style="color: rgba(0, 0, 0, 1)">) {

                        that.MSG.success(res.msg)

                        that.loginSuccess(res)

                  } </span><span style="color: rgba(0, 0, 255, 1)">else</span> {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">result.state==1||reuslt.state==2</span>
<span style="color: rgba(0, 0, 0, 1)">
                        that.MSG.warning(res.msg)

                  }

                })

            },

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">登陆成功</span>
<span style="color: rgba(0, 0, 0, 1)">
            loginSuccess(result) {

                sessionStorage.setItem(</span>'token'<span style="color: rgba(0, 0, 0, 1)">, result.token)

                </span><span style="color: rgba(0, 0, 255, 1)">this</span>.$router.push({ path: '/index'<span style="color: rgba(0, 0, 0, 1)"> })

            }</span></pre>
</div>
<span class="cnblogs_code_collapse">登陆验证</span></div>
<p>获取到的token可以放到sessionStorage、Vuex.Store获取其他存储介质中,方便下次调用接口使用</p>
<p>&nbsp;</p>
<p>2、在main.js文件,在请求拦截方法中,为请求接口加入token</p>
<p>需要注意的是token格式为:‘Bearer ’+token,token参数需要赋值给请求头的Authorization</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_b0b76151-5b17-4517-82d1-10338298bfe3" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_b0b76151-5b17-4517-82d1-10338298bfe3" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_b0b76151-5b17-4517-82d1-10338298bfe3" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">axios.interceptors.request.use(

    config </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">除登陆接口意外的接口都要加上token,才可以请求接口</span>

      <span style="color: rgba(0, 0, 255, 1)">if</span> (!config.url.endsWith('/api/login'<span style="color: rgba(0, 0, 0, 1)">)) {

            </span><span style="color: rgba(0, 0, 255, 1)">if</span>(sessionStorage.getItem('token')!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){

                const token</span>='Bearer '+sessionStorage.getItem('token'<span style="color: rgba(0, 0, 0, 1)">)

                config.headers.common[</span>'Authorization']=<span style="color: rgba(0, 0, 0, 1)">token

            }      

      }

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> config;

    },

    error </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Promise.reject(error);

    }

);</span></pre>
</div>
<span class="cnblogs_code_collapse">axios请求头加token</span></div>
<p>请求头参数格式:</p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/451237/202007/451237-20200717104720537-855692043.png" alt="" loading="lazy"></p><br><br>
来源:https://www.cnblogs.com/eye-like/p/13328535.html
頁: [1]
查看完整版本: Vue+node.js 实现 jwt token验证