jwt是JSON Web Token的缩写,用户登录后,服务器不保存用户信息,而是使用jwt生成一个token给前端,前端每次请求接口的时候都带着这个token,后端只需要对这个token进行验证,只要token正确并且在有效期内即可通过验证,基于token的身份验证可以替代传统的cookie+session身份验证方法。
想更多的了解jwt的原理,可以看一下这篇文章:jwt入门教程
下面我们开始讲jwt在实战中如何使用:
1.安装jwt
github下载地址:https://github.com/lcobucci/jwt
使用composer安装
composer require lcobucci/jwt
2.封装一个jwt操作类
<?php
/**
* jwt封装的一个简单的类
*/
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use DateTimeImmutable;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
class Jwt
{
/**
* 配置秘钥加密
* @return Configuration
*/
public static function getConfig()
{
$configuration = Configuration::forSymmetricSigner(
// You may use any HMAC variations (256, 384, and 512)
new Sha256(),
// replace the value below with a key of your own!
InMemory::base64Encoded('YWFhc0pOU0RLSkJITktKU0RiamhrMTJiM2Joa2ox')
// You may also override the JOSE encoder/decoder if needed by providing extra arguments here
);
return $configuration;
}
/**
* 签发令牌
*/
public static function createToken($uid)
{
$config = self::getConfig();
assert($config instanceof Configuration);
$now = new DateTimeImmutable();
$token = $config->builder()
// 签发人
->issuedBy('https://www.zhiboblog.com')
// 受众
// ->permittedFor('https://www.zhiboblog.com')
// JWT ID 编号 唯一标识
// ->identifiedBy('123')
// 签发时间
->issuedAt($now)
// 在1分钟后才可使用
// ->canOnlyBeUsedAfter($now->modify('+1 minute'))
// 过期时间1小时(1秒之后到期:+1 second,1小时后到期:+1 hour,1分钟后到期:+1 minute)
// ->expiresAt($now->modify('+1 hour'))
// 自定义uid 额外参数
->withClaim('uid', $uid)
// 自定义header 参数
// ->withHeader('foo', 'bar')
// 生成token
->getToken($config->signer(), $config->signingKey());
return $token->toString();
}
/**
* 解析令牌
*/
public static function parseToken($token)
{
$config = self::getConfig();
assert($config instanceof Configuration);
$token = $config->parser()->parse($token);
assert($token instanceof Plain);
// dump($token->headers()); // Retrieves the token headers
// dump($token->claims()); // Retrieves the token claims
//$token->claims()->get('uid');
return $token->claims();
}
/**
* 验证令牌
*/
public static function validateToken($token)
{
$config = self::getConfig();
assert($config instanceof Configuration);
try {
$token = $config->parser()->parse($token);
} catch (\Exception $e) {
return ['status'=>0,'msg'=>'非法token'];
}
assert($token instanceof Plain);
//Lcobucci\JWT\Validation\Constraint\IdentifiedBy: 验证jwt id是否匹配
//Lcobucci\JWT\Validation\Constraint\IssuedBy: 验证签发人参数是否匹配
//Lcobucci\JWT\Validation\Constraint\PermittedFor: 验证受众人参数是否匹配
//Lcobucci\JWT\Validation\Constraint\RelatedTo: 验证自定义cliam参数是否匹配
//Lcobucci\JWT\Validation\Constraint\SignedWith: 验证令牌是否已使用预期的签名者和密钥签名
//Lcobucci\JWT\Validation\Constraint\ValidAt: 验证要求iat,nbf和exp(支持余地配置)
//验证jwt id是否匹配
// $validate_jwt_id = new \Lcobucci\JWT\Validation\Constraint\IdentifiedBy('123');
// $config->setValidationConstraints($validate_jwt_id);
//验证签发人url是否正确
// $validate_issued = new \Lcobucci\JWT\Validation\Constraint\IssuedBy('https://www.zhiboblog.com');
// $config->setValidationConstraints($validate_issued);
//验证客户端url是否匹配
// $validate_aud = new \Lcobucci\JWT\Validation\Constraint\PermittedFor('https://www.zhiboblog.com');
// $config->setValidationConstraints($validate_aud);
//验证是否过期
$timezone = new \DateTimeZone('Asia/Shanghai');
$now = new \Lcobucci\Clock\SystemClock($timezone);
$validate_jwt_at = new \Lcobucci\JWT\Validation\Constraint\ValidAt($now);
$config->setValidationConstraints($validate_jwt_at);
$constraints = $config->validationConstraints();
try {
$config->validator()->assert($token, ...$constraints);
return ['status'=>1,'msg'=>'toekn验证成功'];
} catch (RequiredConstraintsViolated $e) {
// list of constraints violation exceptions:
// var_dump($e->violations());
// return $e->violations();
return ['status'=>0,'msg'=>'toekn验证失败'];
}
}
}
/**
* jwt封装的一个简单的类
*/
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use DateTimeImmutable;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
class Jwt
{
/**
* 配置秘钥加密
* @return Configuration
*/
public static function getConfig()
{
$configuration = Configuration::forSymmetricSigner(
// You may use any HMAC variations (256, 384, and 512)
new Sha256(),
// replace the value below with a key of your own!
InMemory::base64Encoded('YWFhc0pOU0RLSkJITktKU0RiamhrMTJiM2Joa2ox')
// You may also override the JOSE encoder/decoder if needed by providing extra arguments here
);
return $configuration;
}
/**
* 签发令牌
*/
public static function createToken($uid)
{
$config = self::getConfig();
assert($config instanceof Configuration);
$now = new DateTimeImmutable();
$token = $config->builder()
// 签发人
->issuedBy('https://www.zhiboblog.com')
// 受众
// ->permittedFor('https://www.zhiboblog.com')
// JWT ID 编号 唯一标识
// ->identifiedBy('123')
// 签发时间
->issuedAt($now)
// 在1分钟后才可使用
// ->canOnlyBeUsedAfter($now->modify('+1 minute'))
// 过期时间1小时(1秒之后到期:+1 second,1小时后到期:+1 hour,1分钟后到期:+1 minute)
// ->expiresAt($now->modify('+1 hour'))
// 自定义uid 额外参数
->withClaim('uid', $uid)
// 自定义header 参数
// ->withHeader('foo', 'bar')
// 生成token
->getToken($config->signer(), $config->signingKey());
return $token->toString();
}
/**
* 解析令牌
*/
public static function parseToken($token)
{
$config = self::getConfig();
assert($config instanceof Configuration);
$token = $config->parser()->parse($token);
assert($token instanceof Plain);
// dump($token->headers()); // Retrieves the token headers
// dump($token->claims()); // Retrieves the token claims
//$token->claims()->get('uid');
return $token->claims();
}
/**
* 验证令牌
*/
public static function validateToken($token)
{
$config = self::getConfig();
assert($config instanceof Configuration);
try {
$token = $config->parser()->parse($token);
} catch (\Exception $e) {
return ['status'=>0,'msg'=>'非法token'];
}
assert($token instanceof Plain);
//Lcobucci\JWT\Validation\Constraint\IdentifiedBy: 验证jwt id是否匹配
//Lcobucci\JWT\Validation\Constraint\IssuedBy: 验证签发人参数是否匹配
//Lcobucci\JWT\Validation\Constraint\PermittedFor: 验证受众人参数是否匹配
//Lcobucci\JWT\Validation\Constraint\RelatedTo: 验证自定义cliam参数是否匹配
//Lcobucci\JWT\Validation\Constraint\SignedWith: 验证令牌是否已使用预期的签名者和密钥签名
//Lcobucci\JWT\Validation\Constraint\ValidAt: 验证要求iat,nbf和exp(支持余地配置)
//验证jwt id是否匹配
// $validate_jwt_id = new \Lcobucci\JWT\Validation\Constraint\IdentifiedBy('123');
// $config->setValidationConstraints($validate_jwt_id);
//验证签发人url是否正确
// $validate_issued = new \Lcobucci\JWT\Validation\Constraint\IssuedBy('https://www.zhiboblog.com');
// $config->setValidationConstraints($validate_issued);
//验证客户端url是否匹配
// $validate_aud = new \Lcobucci\JWT\Validation\Constraint\PermittedFor('https://www.zhiboblog.com');
// $config->setValidationConstraints($validate_aud);
//验证是否过期
$timezone = new \DateTimeZone('Asia/Shanghai');
$now = new \Lcobucci\Clock\SystemClock($timezone);
$validate_jwt_at = new \Lcobucci\JWT\Validation\Constraint\ValidAt($now);
$config->setValidationConstraints($validate_jwt_at);
$constraints = $config->validationConstraints();
try {
$config->validator()->assert($token, ...$constraints);
return ['status'=>1,'msg'=>'toekn验证成功'];
} catch (RequiredConstraintsViolated $e) {
// list of constraints violation exceptions:
// var_dump($e->violations());
// return $e->violations();
return ['status'=>0,'msg'=>'toekn验证失败'];
}
}
}
3.jwt参数说明
iss 【issuer】签发人(可以是,发布者的url地址)
sub 【subject】该JWT所面向的用户,用于处理特定应用,不是常用的字段
aud 【audience】受众人(可以是客户端的url地址,用作验证是否是指定的人或者url)
exp 【expiration】 该jwt销毁的时间;unix时间戳
nbf 【not before】 该jwt的使用时间不能早于该时间;unix时间戳
iat 【issued at】 该jwt的发布时间;unix 时间戳
jti 【JWT ID】 该jwt的唯一ID编号
sub 【subject】该JWT所面向的用户,用于处理特定应用,不是常用的字段
aud 【audience】受众人(可以是客户端的url地址,用作验证是否是指定的人或者url)
exp 【expiration】 该jwt销毁的时间;unix时间戳
nbf 【not before】 该jwt的使用时间不能早于该时间;unix时间戳
iat 【issued at】 该jwt的发布时间;unix 时间戳
jti 【JWT ID】 该jwt的唯一ID编号
4.使用
<?php
//生成token
Jwt::createToken($uid);
//解析token
Jwt::parseToken($token);
//验证token
Jwt::validateToken($token);
//生成token
Jwt::createToken($uid);
//解析token
Jwt::parseToken($token);
//验证token
Jwt::validateToken($token);