token 的生成杂谈

32

背景

很多时候我们需要用 token 来作为一些标识, 比如: 一个用户登录后的认证标识.

实现方式

md5 的方式:

$v = 1; // 自己定义的 需要hash 的value 值
$key = mt_rand(); // 这里用 随机串作为key
$hash = md5($key . $v . mt_rand() . time());
echo $hash;

执行结果: b63426a38f86b726ce0d327d48e47376 看着不是很舒服, 作为强迫症的我 是受不了的.

md5 + base64 的方式

$v = 1;
$key = mt_rand();
$hash = md5($key . $v . mt_rand() . time());
$token = base64_encode($hash);
echo $token;

执行结果: MWQyMjE2NmI3NDA1MmRjZTQwOTQzZDZjMWU1OTE5OGU= 看着稍微舒服些了, 但是还不够好, 反观微信的 openid , 一般是不会有后面的 = 号的

优化

$v = 1;
$key = mt_rand();
$hash = md5($key . $v . mt_rand() . time());
$token = str_replace('=', '', base64_encode($hash));
echo $token;

执行结果: Yzg4MWU0OTQ0MTRiZTI0YWYwMDJjOTYyODBkNjFmMTM 这下没有 = 号了, 舒服了些, 但是又太长了, 微信的 openid 可没这么长

换种 hash 试试

sha1 + base64 的方式

$v = 1;
$key = mt_rand();
$hash = hash_hmac("sha1", $v . mt_rand() . time(), $key, true);
$token = str_replace('=', '', base64_encode($hash));
echo $token;

执行结果: 7pn0pWzO+/TOoISNtDaewa4CyuXw 是短些了, 可是里面有 +/ 号, 很多情况下用 get 传递时会被 urlcode, urlcode 过后就这样了 7pn0pWzO%2b%2fTOoISNtDaewa4CyuXw, 这显然不是我们想要的

继续优化
$v = 1;
$key = mt_rand();
$hash = hash_hmac("sha1", $v . mt_rand() . time(), $key, true);
$token = str_replace('=', '', strtr(base64_encode($hash), '+/', '-_'));
echo $token;

执行结果: JM9AkY7SAIROrJ7fhjIU2ApbMsI 这下不会 urlcode了, 看着也舒服些了, 我目前是这样用的...

但是这是不是最优方案呢?

目前没发现什么更好的方案, 只是说出了我认为的比较好的方案

Vue-cli3.0 + Element UI + ThinkPHP5.1 + RBAC权限 + 响应式的后台管理系统

你可能感兴趣的

19 条评论
fuzqing · 2018年07月22日

贴个方法:

private function createRandomString($length = 32) {

    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    $string = '';

    for ($i = 0; $i < $length; $i++) {

        $string .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);

    }

    return $string;
}

result:

CWHN7JwHzEr4VwPjXFiwYR31wKvO0JQK

+1 回复

0

这个不错

lmxdawn 作者 · 2018年07月22日
0

这不是微信sdk里的的getNonceStr么- -

夜影 · 2018年07月23日
0

你这个没办法保证全局唯一,适合唯一性没那么强的场景。

lifei6671 · 2018年07月23日
Birjemin · 2018年07月23日

个人觉得一般这种token都是有特殊含义的,比如线上出问题了,我只找到了这个token线索,我该如何定位是哪个用户什么时候触发了bug?这样我才能追踪数据的走向。或者一些常用频繁的数据(user_id)避免频繁去取(cache,db...)
例如:
<?php
echo base_64_encode($appSecret . '_' . $userId . '_' . uniqid() );
?>
所以个人觉得token最好具有实际意义,可解码,可表示唯一性,时效性可控(比如迭代新版本,需要强制用户重新登录,将token的secret更改使之失效,让用户重新登录)。另外hashids这个库很棒!

+1 回复

0

我这个是 token 用做key,然后根据这个key去数据库或者 redis 查询用户信息

lmxdawn 作者 · 2018年07月27日
0

这样啊,那我可能理解错了“很多时候我们需要用 token 来作为一些标识, 比如: 一个用户登录后的认证标识.”

Birjemin · 2018年07月30日
不良锦衣 · 2018年07月22日

什么鬼

回复

JaysonWang · 2018年07月22日

md5摘要之后的值和你最后千辛万苦搞出来的值,有啥本质上的差别么??不都一样是个随机字符串…

回复

0

只是个人拙见,不在讨论范围

lmxdawn 作者 · 2018年07月23日
CrazyCodes · 2018年07月22日

继续努力,小伙
token 我感觉应该是 用户的一些信息+时间戳+appkey(类似微信的appkey,定时更换着点)

回复

0

你说的 貌似都有,$v 不就是用户信息么

lmxdawn 作者 · 2018年07月23日
徐小说 · 2018年07月23日

jwt 了解一下

回复

0

恩,jwt 和我这场景不一样的。。。

lmxdawn 作者 · 2018年07月23日
0

@兰茗翔 场景其实一样的,你自己设计的这种t不带任何信息的随机加密串,需要加张表存储token和用户的关联表,需要做数据约束(toekn userid 联合唯一),还可能会上redis。。。。。但是功能也就是实现 鉴权和不可伪造

硪对沵始终如⒈ · 2018年07月28日
tim1020 · 2018年07月27日

没get到md5跟强迫症有什么关联? 不都是一堆乱序字符串吗?嫌长就substr一下。后面的方法大小写混排对我来说更难接受

回复

来5块钱代码 · 2018年08月02日

echo bin2hex(openssl_random_pseudo_bytes(10));

回复

载入中...