二:JWT优点:

1:做事端不须要保存传统会话信息,没有跨域传输问题,减小做事器开销。

2:jwt构成大略,占用很少的字节,便于传输。

firebasephpjwt文档php firebase/phpjwt token验证还在用session吗 GraphQL

3:json格式通用,不同措辞之间都可以利用。

三:JWT组成

1:jwt由三部分组成:

头部(header)

载荷(payload) 包含一些定义信息和自定义信息

签证(signature)

2:详细构成:

header:

{

\"大众typ\公众: \公众JWT\"大众, //声明类型为jwt

\"大众alg\公众: \公众HS256\"大众 //声明署名算法为SHA256

}

载荷(payload)

{

\"大众iss\"大众: \"大众http://www.helloweba.net\"大众,

\"大众aud\公众: \"大众http://www.helloweba.net\公众,

\公众iat\"大众: 1525317601,

\公众nbf\"大众: 1525318201,

\"大众exp\"大众: 1525318201,

\公众data\"大众: {

\公众userid\公众: 1,

\公众username\"大众: \公众李小龙\"大众

}

}

载荷包括两部分:标准声明和其他声明。

标准声明:JWT标准规定的声明,但不是必须填写的;

标准声明字段:

吸收该JWT的一方

iss: jwt签发者

sub: jwt所面向的用户

aud: 吸收jwt的一方

exp: jwt的过期韶光,过期韶光必须要大于签发韶光

nbf: 定义在什么韶光之前,某个韶光点后才能访问

iat: jwt的签发韶光

jti: jwt的唯一身份标识,紧张用来作为一次性token

其他声明:自己定义的字段,由于这部分是可以解开的,建议不要加入敏感信息,这里的data便是我自己定义的声明

终极是这样的:

三部分分别以逗号隔开

四:利用:PHP有很多jwt包,包括比如:lcobucci/jwt,我这里利用firebase。
可以从 git地址 下载

1:把代码拉取下来

composer require firebase/php-jwt

2:做事端签发Token

<?php

use \Firebase\JWT\JWT; //导入JWT

class MainController extends Controller

{

//签发Token

public function lssue()

{

$key = '344'; //key

$time = time(); //当前韶光

$token = [

'iss' => 'http://www.helloweba.net', //签发者 可选

'aud' => 'http://www.helloweba.net', //吸收该JWT的一方,可选

'iat' => $time, //签发韶光

'nbf' => $time , //(Not Before):某个韶光点后才能访问,比如设置time+30,表示当前韶光30秒后才能利用

'exp' => $time+7200, //过期韶光,这里设置2个小时

'data' => [ //自定义信息,不要定义敏感信息

'userid' => 1,

'username' => '李小龙'

]

];

echo JWT::encode($token, $key); //输出Token

}

}

3:解析Token,为了演示,这里直接写。

<?php

use \Firebase\JWT\JWT; //导入JWT

class MainController extends Controller

{

public function verification()

{

$key = '344'; //key要和签发的时候一样

$jwt = \"大众eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuaGVsbG93ZWJhLm5ldCIsImF1ZCI6Imh0dHA6XC9cL3d3dy5oZWxsb3dlYmEubmV0IiwiaWF0IjoxNTI1MzQwMzE3LCJuYmYiOjE1MjUzNDAzMTcsImV4cCI6MTUyNTM0NzUxNywiZGF0YSI6eyJ1c2VyaWQiOjEsInVzZXJuYW1lIjoiXHU2NzRlXHU1YzBmXHU5Zjk5In19.Ukd7trwYMoQmahOAtvNynSA511mseA2ihejoZs7dxt0\"大众; //签发的Token

try {

JWT::$leeway = 60;//当前韶光减去60,把韶光留点余地

$decoded = JWT::decode($jwt, $key, ['HS256']); //HS256办法,这里要和签发的时候对应

$arr = (array)$decoded;

print_r($arr);

} catch(\Firebase\JWT\SignatureInvalidException $e) { //署名禁绝确

echo $e->getMessage();

}catch(\Firebase\JWT\BeforeValidException $e) { // 署名在某个韶光点之后才能用

echo $e->getMessage();

}catch(\Firebase\JWT\ExpiredException $e) { // token过期

echo $e->getMessage();

}catch(Exception $e) { //其他缺点

echo $e->getMessage();

}

//Firebase定义了多个 throw new,我们可以捕获多个catch来定义问题,catch加入自己的业务,比如token过期可以用当前Token刷新一个新Token

}

}

在src目录下的JWT.php中的方法 decode中,可以看到作者是通过多个 自定义 throw new 抛出非常的

以是我们可以根据不同的throw new设置多个catch来捕获。

输出的数据:

Array

(

[iss] => http://www.helloweba.net

[aud] => http://www.helloweba.net

[iat] => 1525340317

[nbf] => 1525340317

[exp] => 1525347517

[data] => stdClass Object

(

[userid] => 1

[username] => 李小龙

)

)

五:仿照实战

1:方案:客户端通过用户名密码登录往后,做事端返回给客户端两个token:access_token和refresh_token。

access_token:要求接口的token

refresh_token:刷新access_token

举个例子:比如access_token设置2个小时过期,refresh_token设置7天过期,2小时候后,access_token过期,但是refresh_token还在7天以内,那么客户端通过refresh_token来做事端刷新,做事端重新天生一个access_token;如果refresh_token也超过了7天,那么客户端须要重新登录获取access_token和refresh_token。

为了区分两个token,我们在载荷(payload)加一个字段 scopes :浸染域。

access_token中设置:scopes:role_access

refresh_token中设置:scopes:role_refresh

有些人是用一个token,要么设置很永劫光过期;要么设置几个小时过期,如果过期,用过期的token去换取新的token,这种实在是有问题的,有些人说token有两个韶光,一个是过期韶光,一个是刷新韶光,只要在刷新韶光内就可以换取新token。
如果别人拿到了你这token,如果也在过期韶光之内,不是同样可以刷新token?除非两个token都拿到,相对来说第二种更安全。

直接上代码:

<?php

use \Firebase\JWT\JWT; //导入JWT

class MainController extends Controller

{

public function authorizations()

{

$key = 'ffdsfsd@4_45'; //key

$time = time(); //当前韶光

//公用信息

$token = [

'iss' => 'http://www.helloweba.net', //签发者 可选

'iat' => $time, //签发韶光

'data' => [ //自定义信息,不要定义敏感信息

'userid' => 1,

]

];

$access_token = $token;

$access_token['scopes'] = 'role_access'; //token标识,要求接口的token

$access_token['exp'] = $time+7200; //access_token过期韶光,这里设置2个小时

$refresh_token = $token;

$refresh_token['scopes'] = 'role_refresh'; //token标识,刷新access_token

$refresh_token['exp'] = $time+(86400 30); //access_token过期韶光,这里设置30天

$jsonList = [

'access_token'=>JWT::encode($access_token,$key),

'refresh_token'=>JWT::encode($refresh_token,$key),

'token_type'=>'bearer' //token_type:表示令牌类型,该值大小写不敏感,这里用bearer

];

Header(\"大众HTTP/1.1 201 Created\"大众);

echo json_encode($jsonList); //返回给客户端token信息

}

}

看起来输出是这样的:

{

\公众access_token\公众: \"大众eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuaGVsbG93ZWJhLm5ldCIsImlhdCI6MTUyNTQxNzg5NywiZGF0YSI6eyJ1c2VyaWQiOjF9LCJzY29wZXMiOiJyb2xlX2FjY2VzcyIsImV4cCI6MTUyNTQyNTA5N30.Nxp1yutwt8Fxj5XEzes4j-X4tCBQwE0htEV3Msm2D8s\公众,

\"大众refresh_token\"大众: \"大众eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuaGVsbG93ZWJhLm5ldCIsImlhdCI6MTUyNTQxNzg5NywiZGF0YSI6eyJ1c2VyaWQiOjF9LCJzY29wZXMiOiJyb2xlX3JlZnJlc2giLCJleHAiOjE1MjgwMDk4OTd9.YY8Lid3nk3bnV-ZnAYneKJxGiaD73waqTpC3bHz3wsY\"大众,

\"大众token_type\"大众: \"大众bearer\公众

}

http头部相应是这样的:两个token客户端保存,一个用来取接口,一个用来刷新接口。

客户端要求的时候在http头部携带 Authorization: bearer token,把稳bearer后面有个空格,我们用PHP仿照一下。

要求信息是这样的,PHP获取Authorization信息判断。

这个只是一种思路,大家可以按照自己的思路去弄,这种思路做事端不用保存token,但如果涉及到token的注销就必须保存,比如token没过期,但是要注销token,这时候可以上redis。

末了请务必利用HTTPS