svip7

JWT,全称 Json web token,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

php实现JWT,本例使用thinkphp框架,代码如下:

在vendor包中建立Jwt.php,建立类文件

class Jwt {
 
 //头部
 private static $header=array(
  \'alg\'=>\'HS256\', //生成signature的算法
  \'typ\'=>\'JWT\' //类型
 );
 
 //使用HMAC生成信息摘要时所使用的密钥
 private static $key=\'123456\';
 
 
 /**
  * 获取jwt token
  * @param array $payload jwt载荷 格式如下非必须
  * [
  * \'iss\'=>\'jwt_admin\', //该JWT的签发者
  * \'iat\'=>time(), //签发时间
  * \'exp\'=>time()+7200, //过期时间
  * \'nbf\'=>time()+60, //该时间之前不接收处理该Token
  * \'sub\'=>\'www.admin.com\', //面向的用户
  * \'jti\'=>md5(uniqid(\'JWT\').time()) //该Token唯一标识
  * ]
  * @return bool|string
  */
 public static function getToken($payload)
 {
  if(is_array($payload))
  {
   $base64header=self::base64UrlEncode(json_encode(self::$header,JSON_UNESCAPED_UNICODE));
   $base64payload=self::base64UrlEncode(json_encode($payload,JSON_UNESCAPED_UNICODE));
   $token=$base64header.\'.\'.$base64payload.\'.\'.self::signature($base64header.\'.\'.$base64payload,self::$key,self::$header[\'alg\']);
   return $token;
  }else{
   return false;
  }
 }
 
 
 /**
  * 验证token是否有效,默认验证exp,nbf,iat时间
  * @param string $Token 需要验证的token
  * @return bool|string
  */
 public static function verifyToken($Token)
 {
  $tokens = explode(\'.\', $Token);
  if (count($tokens) != 3)
   return false;
 
  list($base64header, $base64payload, $sign) = $tokens;
 
  //获取jwt算法
  $base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);
  if (empty($base64decodeheader[\'alg\']))
   return false;
 
  //签名验证
  if (self::signature($base64header . \'.\' . $base64payload, self::$key, $base64decodeheader[\'alg\']) !== $sign)
   return false;
 
  $payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);
 
  //签发时间大于当前服务器时间验证失败
  if (isset($payload[\'iat\']) && $payload[\'iat\'] > time())
   return false;
 
  //过期时间小宇当前服务器时间验证失败
  if (isset($payload[\'exp\']) && $payload[\'exp\'] < time())
   return false;
 
  //该nbf时间之前不接收处理该Token
  if (isset($payload[\'nbf\']) && $payload[\'nbf\'] > time())
   return false;
 
  return $payload;
 }
 
 
 
 
 /**
  * base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现
  * @param string $input 需要编码的字符串
  * @return string
  */
 private static function base64UrlEncode($input)
 {
  return str_replace(\'=\', \'\', strtr(base64_encode($input), \'+/\', \'-_\'));
 }
 
 /**
  * base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现
  * @param string $input 需要解码的字符串
  * @return bool|string
  */
 private static function base64UrlDecode($input)
 {
  $remainder = strlen($input) % 4;
  if ($remainder) {
   $addlen = 4 - $remainder;
   $input .= str_repeat(\'=\', $addlen);
  }
  return base64_decode(strtr($input, \'-_\', \'+/\'));
 }
 
 /**
  * HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现
  * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
  * @param string $key
  * @param string $alg 算法方式
  * @return mixed
  */
 private static function signature($input, $key, $alg = \'HS256\')
 {
  $alg_config=array(
   \'HS256\'=>\'sha256\'
  );
  return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key,true));
 }
}

调用JWT验证的方法,代码如下:

1.构建token方法

public function makeToken(){
     $uname=$this->uname;    $currtime=time();
     if(empty($this->uname)){ echo json_encode(array(\'code\'=>-1,\'msg\'=>\'[主账号]参数为空\'),JSON_UNESCAPED_UNICODE);    exit(); }    
     ....
     //jwt验证
     vendor("Jwt.Jwt");
     $jwt = new \Jwt();
//这里构造jwt参数,可以参照jwt规范,各字段可以自行定义内容     $payload=array(\'iss\'=>\'xesport\',\'sub\'=>\'xxx_player\',\'name\'=>$playerName,\'iat\'=>$currtime,\'jti\'=>md5(uniqid(\'JWT\').$currtime));
     $token=$jwt->getToken($payload); $this->token=$token;
     $url=\'http://xxx?token=\'.$token;
     $data=array(\'url\'=>$url);
     
     echo json_encode(array(\'code\'=>1,\'data\'=>$data,),JSON_UNESCAPED_UNICODE); exit();
 
    }

2.验证token的方法

//验证token
public function verifyToken(){
     $token=$_REQUEST[\'token\'];
     if(empty($token)){ echo json_encode(array(\'code\'=>-1,\'msg\'=>\'[token]参数为空!\'),JSON_UNESCAPED_UNICODE);    exit(); }
  vendor("Jwt.Jwt");
     $jwt = new \Jwt();     
     $res_token=$jwt->verifyToken($token);
  //var_dump(\'res_token==\',$res_token);
     if(empty($res_token)){ echo json_encode(array(\'code\'=>-2,\'msg\'=>\'[token]验证失败!\'),JSON_UNESCAPED_UNICODE);    exit(); }
     $playerName=$res_token[\'name\'];
     //echo $playerName; die;
     这里可以写从数据库查询验证user是否存在,返回 $userInfo 
     if(empty($userInfo)){ echo json_encode(array(\'code\'=>-3,\'msg\'=>\'[token]验证用户无效!\'),JSON_UNESCAPED_UNICODE);    exit(); }
     $data=array(\'username\'=>$playerName);
     echo json_encode(array(\'code\'=>1,\'data\'=>$data,\'msg\'=>\'[token]验证成功\'),JSON_UNESCAPED_UNICODE);    exit();
    }

这样,我们通过控制器方法调用该方法,传递参数token,就可以解析token中包含的认证凭据信息,从而做后续业务处理逻辑。

分类:

技术点:

相关文章: