场景描述
让我们来假想一下一个场景。在A用户关注了B用户的时候,系统发邮件给B用户,并且附有一个链接“点此关注A用户”。链接的地址可以是这样的:https://your.awesome-app.com/make-friend/?from_user=B&target_user=A
上面的URL主要通过URL描述来实现这个功能,这样做有一个弊端,那就是要求用户B用户是一定要先登录的。
思考:可不可以简化这个流程?让B用户不用登录就可以完成这个操作。
思路分析
前面的文章已经说到,jwt的playload可以存放自定义信息,虽然信息会暴露,不建议存放敏感信息,但是我们在该业务场景中,只需要用到用户名,用户名也不是什么敏感信息,第二个考虑点,则是需要防止篡改。
一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小(有可能比我成世界首富的概率还小)。所以,我们就把“不一样的输入产生不一样的输出”当做必然事件来看待吧。
正确的签名
所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。
篡改的签名
思路分析完成,只需要把我们原来的链接,后边拼接jwt加密串,即可完成该功能。如:https://your.awesome-app.com/make-friend/?from_target=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDB9.KcNaeDRMPwkRHDHsuIh1L2B01VApiu3aTOkWplFjoYI
准备工作
$key = "example_key";
$token = array(
"iss" => "http://example.org",
"aud" => "http://example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
$jwt = JWT::encode($token, $key);
$decoded = JWT::decode($jwt, $key, array('HS256'));
//返回的是一个obj对象
print_r($decoded);
$decoded_array = (array)$decoded;
//转化为数组
print_r($decoded_array);
编码
public function send_sys_email()
{
$key = "example_key";
$token = array(
"iss" => "https://iffor.cn",
"aud" => "https://iffor.cn",
"iat" => 1356999524,
"nbf" => 1357000000,
"from_user"=>"B",
"target_user"=>"A"
);
$jwt = JWT::encode($token, $key);
$url = "https://iffor.cn/api/jwtdemo/make_friend/?from_target=".$jwt;
//模拟 邮件内容
echo "亲爱的用户,新粉丝提示,刚刚【A用户】关注了您,<a href='$url'>「点击」</a>互相关注。";
}
模拟效果图
public function make_friend()
{
$key = "example_key";
$jwt = input('get.from_target');
$decoded = JWT::decode($jwt, $key, array('HS256'));
$decoded_array = (array)$decoded;
dump($decoded_array);
}
解密效果图
根据解密出来的from_user与target_user做对应的关注逻辑处理。
网友评论