connect time out 获取token失败_基于JWT的Token登录认证

JWT简介 :

json Web Token(缩写JWT)是目前最流行的跨域认证解决方案

session登录的认证方案是看,用户从客户端传递用户名和密码登录信息,服务端认证后将信息储存在session中,将session_id放入cookie中,以后访问其他页面,服务器都会带着cookie,服务端会自动从cookie中获取session_id,在从session中获取认证信息。

JWT的解决方案是,将认证信息返回个客户端,储存在客户端,下次访问其他页面,需要从客户端传递认证信息回服务器端。

那么有人会问,将认证信息个客户端了,那么有坏人恶意修改,然后传递个服务器端怎么办呢,这个问题下面说JWT原理就会说到

JWT原理

JWT原理就是,服务器认证后,生成一个json格式的对象 ,发送个客户端,

{
"用户名": "admin",
"角色": "超级管理员",
"到期时间": "2019-07-13 00:00:00"
}

以后,客户端域服务器通信的时候,都要发回这个json对象,服务器完全靠这个对象认定用户身份,(但肯定不会像上面那样,那么简单的发送一个对象)这样的话,session中就没有数据了,后面更容易实现扩展

JWT的数据结构

JWT分为三个部分,header(头部) payload (负载) signature (签名)

一个完整的JWT数据是这样的

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjNmMmc1N2E5MmFhIn0.
eyJpYXQiOjE1NjI4MzM0MDgsImlzcyI6Imh0dHA6XC9cL3d3dy5weWcuY29tIiwiYXVkIjoiaHR0cDpcL1wvd3d3LnB5Zy5jb20iLCJuYmYiOjE1NjI4MzM0MDcsImV4cCI6MTU2MjkxOTgwOCwianRpIjoiM2YyZzU3YTkyYWEiLCJ1c2VyX2lkIjoxfQ.
NFq1qQ-Z5c4pwit8ZkyWEwX6SBXmnHJcc6ZDgSD5nhU

中间是有三个点的,分别就是 头部 负载 和签名 (点在每一行的最后)

头部 是一个json对象 作用是描述JWT元数据,一般是这样的

{
"alg": "HS256",      //表示签名的算法默认是 HMAC SHA256(写成 HS256)
"typ": "JWT"         //表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
}

最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。

负载 也是一个 JSON 对象 ,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用

5fd58625d954d5fdcfbb49f26ba3f239.png

除了官方字段,你还可以在这个部分定义私有字段

这个 JSON 对象也要使用 Base64URL 算法转成字符串(防止除了用户的人看见嘛)。

注意:JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。(虽然加密了,防止解密的坏人解密后修改在加密)

签名 是对前两部分的签名(可以理解成在加密一份),防止数据篡改。

首先,需要指定一个密钥(自己设置),这个密钥只有服务器才知道,不能泄露给用户。

使用 Header 里面指定的签名算法(默认是 HMAC SHA256)产生签名

如:HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)     //使用Header 里面指定的签名算法  将头部和负载部用逗号拼接起来,在加上自己设置的秘钥

那么签名就出来的。

签名出来后,现在有了 头部的字符串,和负载的字符串 ,还有签名的,在将这三个字符串用 . 拼接出来,就可以将这个拼接好的字符串,返回给客户端的

JWT数据就返回得了客户端,需要注意的是,头部和负载部,是用base64URL转成字符串的,签名是用头部指定的算法转成字符串的 不用弄混掉

JWT 的使用方式

客户端,接受到了服务器返回的jwt,可以储存到cookie中,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

一旦我们使用的JWT,JWT的类别人封装好的,会自动将生成的token放入响应头中去,然后再次去访问页面的时候会带着响应回来token去访问页面

JWT在请求头中发送,如:会多了个请求头

Authorization: Bearer <token>  

然后,在服务器中,需要验证这个token,是否有效

下面是实际应用在tp框架中

当然需要通过composer安装JWT类

composer require lcobucci/jwt 3.3         //安装jwt

定义一个专门生成,和验证JWT的token

<?php
namespace toolsjwt;
use LcobucciJWTBuilder; //生成token类
use LcobucciJWTParser;//解析token
use LcobucciJWTSignerHmacSha256; //签名加密类
use LcobucciJWTValidationData;//检测token


class Token //在扩展中加入一个叫工具和jwt的文件夹,里面写入一个叫token的类
{
    private static $_config = [ //生成token的基本参数
        'audience' => 'http://www.mypyg.com',//接收人
        'id' => 'zyt6b',//token的唯一www.pyg.com标识,这里只是一个简单示例
        'sign' => 'zyt6b',//签名密钥
        'issuer' => 'http://adminapi.pyg.com',//签发人
        'expire' => 3600*24 //有效期
    ];

    //生成token
    public static function getToken($user_id){//传来的用户id生成token

        //签名对象
        $signer = new Sha256(); //获取签名对象数据
        //获取当前时间戳
        $time = time();
        //设置签发人、接收人、唯一标识、签发时间、立即生效、过期时间、用户id、签名
        $token = (new Builder())->issuedBy(self::$_config['issuer'])//签发人
            ->canOnlyBeUsedBy(self::$_config['audience'])//接收人
            ->identifiedBy(self::$_config['id'], true)//标识id
            ->issuedAt($time)//签发时间
            ->canOnlyBeUsedAfter($time-1) //生效时间
            ->expiresAt($time + self::$_config['expire'])//过期时间
            ->with('user_id', $user_id) //用户id加入token
            ->sign($signer, self::$_config['sign']) //签名秘钥
            ->getToken();  //用上面信息生成token 
        return (string)$token; //强制返回字符串token
    }

    //从请求信息中获取token令牌
    public static function getRequestToken()
    {//在public里重写apache ,因为不处理,php中接收不到HTTP_AUTHORAZATION字段信息
             //在public/.htaccess 中添加以下两行代码
             //RewriteCond %{HTTP:Authorization} ^(.+)$
             //RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

        if (empty($_SERVER['HTTP_AUTHORIZATION'])) { //判断有没有AUTHORIZATION字段的信息
            return false;                             //server可以获得请求头信息
        }
        //如果有AUTHORIZATION:就写入变量
        $header = $_SERVER['HTTP_AUTHORIZATION'];
        $method = 'bearer';
        //去除token中可能存在的bearer标识
        return trim(str_ireplace($method, '', $header));//忽略大小写,去除字符串首尾的空白字符
        //将 $header 中的所有$method替换成'';
        //获取的时候去除多余的东西,只留一个token
    }

    //从token中获取用户id (包含token的校验)
    public static function getUserId($token = null)
    {
        $user_id = null;
        
        //判断$token是否是空,如果是空的话就从请求信息中获取token,否则就用自己
        $token = empty($token)?self::getRequestToken():$token;
        //判断$token是否是空
        return $token;die;
        if (!empty($token)) { //如果token不是空
            //为了注销token 加以下if判断代码
            $delete_token = cache('delete_token') ?: [];
            //从缓存中取出被标注被删除的token
            if(in_array($token, $delete_token)){//判断当前的token是否缓存中的删除中的token
                //token已被删除(注销)
                return $user_id;//如果在里面,返回用户id
            }
            $token = (new Parser())->parse((string) $token);//解析token
            $data = new ValidationData();//验证token的类
            $data->setIssuer(self::$_config['issuer']);//验证的签发人
            $data->setAudience(self::$_config['audience']);//验证的接收人
            $data->setId(self::$_config['id']);//验证token标识

            if (!$token->validate($data)) { //如果验证失败
                return $user_id; //返回用户id
            }
            
            $signer = new Sha256(); //验证签名秘钥的类
            if (!$token->verify($signer, self::$_config['sign'])) {//验证签名秘钥
                //签名验证失败 //token通过秘钥和加密的类的 看看能不能解析出来东西
                return $user_id;
            }
            //从token中获取用户id
            $user_id = $token->getClaim('user_id');
        }

        return $user_id; //返回用户id 这里应该有值
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值