token 验证详解实例

<div class="maincontent">
                                                            <h1 class="page-header">基于 Token 的身份验证</h1>
                                        <div id="node-2834" class="node node-blog view-mode-full clearfix" about="/blog/2834" typeof="sioc:Item foaf:Document">      <span property="dc:title" content="基于 Token 的身份验证" class="rdf-meta element-hidden"></span><span property="sioc:num_replies" content="7" datatype="xsd:integer" class="rdf-meta element-hidden"></span>    <div class="node-content">
        <div class="content">
                <p>最近了解下基于 Token 的身份验证,跟大伙分享下。很多大型网站也都在用,比如&nbsp;Facebook,Twitter,Google+,Github 等等,比起传统的身份验证方法,Token 扩展性更强,也更安全点,非常适合用在 Web 应用或者移动应用上。Token 的中文有人翻译成 “令牌”,我觉得挺好,意思就是,你拿着这个令牌,才能过一些关卡。</p>
<h2>传统身份验证的方法</h2>
<p>HTTP 是一种没有状态的协议,也就是它并不知道是谁是访问应用。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。</p>
<p>解决的方法就是,当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的 ID 号发送给客户端,客户端收到以后把这个 ID 号存储在 Cookie 里,下次这个用户再向服务端发送请求的时候,可以带着这个 Cookie ,这样服务端会验证一个这个 Cookie 里的信息,看看能不能在服务端这里找到对应的记录,如果可以,说明用户已经通过了身份验证,就把用户请求的数据返回给客户端。</p>
<p>上面说的就是 Session,我们需要在服务端存储为登录的用户生成的 Session ,这些 Session 可能会存储在内存,磁盘,或者数据库里。我们可能需要在服务端定期的去清理过期的 Session 。</p>
<h2>基于 Token 的身份验证方法</h2>
<p>使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:</p>
<ol><li>客户端使用用户名跟密码请求登录</li>
<li>服务端收到请求,去验证用户名与密码</li>
<li>验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端</li>
<li>客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里</li>
<li>客户端每次向服务端请求资源的时候需要带着服务端签发的 Token</li>
<li>服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据</li>
</ol><h2>JWT</h2>
<p>实施 Token 验证的方法挺多的,还有一些标准方法,比如 JWT,读作:jot ,表示:JSON Web Tokens 。JWT 标准的 Token 有三个部分:</p>
<ul><li>header</li>
<li>payload</li>
<li>signature</li>
</ul><p>中间用点分隔开,并且都会使用 Base64 编码,所以真正的 Token 看起来像这样:</p>
<pre class="hljs css"><span class="hljs-selector-tag">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</span><span class="hljs-selector-class">.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ</span><span class="hljs-selector-class">.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc</span></pre><h3>Header</h3>
<p>header 部分主要是两部分内容,一个是 Token 的类型,另一个是使用的算法,比如下面类型就是 JWT,使用的算法是 HS256。</p>
<pre class="hljs json">{
  <span class="hljs-attr">"typ"</span>: <span class="hljs-string">"JWT"</span>,
  <span class="hljs-attr">"alg"</span>: <span class="hljs-string">"HS256"</span>
}</pre><p>上面的内容要用 Base64 的形式编码一下,所以就变成这样:</p>
<pre class="hljs">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</pre><h3>Payload</h3>
<p>Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。下面是标准字段:</p>
<ul><li>iss:Issuer,发行者</li>
<li>sub:Subject,主题</li>
<li>aud:Audience,观众</li>
<li>exp:Expiration time,过期时间</li>
<li>nbf:Not before</li>
<li>iat:Issued at,发行时间</li>
<li>jti:JWT ID</li>
</ul><p>比如下面这个 Payload ,用到了 iss 发行人,还有 exp 过期时间。另外还有两个自定义的字段,一个是 name ,还有一个是 admin 。</p>
<pre class="hljs json">{
 <span class="hljs-attr">"iss"</span>: <span class="hljs-string">"ninghao.net"</span>,
 <span class="hljs-attr">"exp"</span>: <span class="hljs-string">"1438955445"</span>,
 <span class="hljs-attr">"name"</span>: <span class="hljs-string">"wanghao"</span>,
 <span class="hljs-attr">"admin"</span>: <span class="hljs-literal">true</span>
}</pre><p>使用 Base64 编码以后就变成了这个样子:</p>
<pre class="hljs">eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ</pre><h3>Signature</h3>
<p>JWT 的最后一部分是 Signature ,这部分内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端。</p>
<ul><li>header</li>
<li>payload</li>
<li>secret</li>
</ul><pre class="hljs javascript"><span class="hljs-keyword">var</span> encodedString = base64UrlEncode(header) + <span class="hljs-string">"."</span> + base64UrlEncode(payload); 
HMACSHA256(encodedString, <span class="hljs-string">'secret'</span>);</pre><p>处理完成以后看起来像这样:</p>
<pre class="hljs">SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc</pre><p>最后这个在服务端生成并且要发送给客户端的 Token 看起来像这样:</p>
<pre class="hljs css"><span class="hljs-selector-tag">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</span><span class="hljs-selector-class">.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ</span><span class="hljs-selector-class">.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc</span></pre><p>客户端收到这个 Token 以后把它存储下来,下回向服务端发送请求的时候就带着这个 Token 。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。</p>
<h2>相关链接</h2>
<ul><li><a href="http://jwt.io/">http://jwt.io/</a></li>
<li><a href="https://github.com/firebase/php-jwt">https://github.com/firebase/php-jwt</a></li>
<li><a href="https://scotch.io/tutorials/the-anatomy-of-a-json-web-token">https://scotch.io/tutorials/the-anatomy-of-a-json-web-token</a></li>
<li><a href="https://github.com/auth0/jwt-decode">https://github.com/auth0/jwt-decode</a></li>
</ul>         </div>
  </div>
  </div>
</div>
<!-- /.node --> 
        </div>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值