在例如身份验证场景中,用户一旦登陆,接下来的每一个请求都会包含jwt,用来验证身份信息。因为通讯双方使用jwt对数据进行编码,它的信息是通过签名的,因此能够确保信息的安全性.算法
cookie缺点mongodb
jwt优势json
咱们先来看看JWT的是怎么生成的?JWT是一种规范.他由下面的一种结构构造而成.跨域
header.payload.signature
复制代码
JWT 的 Header 部分包含有关如何计算 JWT 签名的信息,是一个如下形式的 JSON 对象:浏览器
{
"typ": "JWT",
"alg": "HS256"
}
复制代码
在上面的 JSON 中,“typ”键的值指定对象是JWT,“alg”键的值指定用于建立 JWT 签名的算法。 在示例中,咱们使用 HMAC-SHA256算法(一种使用密钥的散列算法)来计算签名(在步骤3中会更详细的介绍)。安全
建立 PAYLOADbash
JWT 的 payload 部分时是存储在 JWT 内的数据。在咱们的示例中,身份验证服务器建立一个JWT,其中存储有用户信息,特别是用户ID。服务器
{
"userId": "b08f86af-35da-48f2-8fab-cef3904660bd"
}
复制代码
在咱们的示例中,咱们只将一个声明放入 payload 中。 你能够根据须要添加任意数量的声明。JWT 规定了7个官方字段,供选用。cookie
iss (issuer):签发人
exp (expiration time):过时时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
复制代码
建立 SIGNATURE网络
// signature algorithm
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
hashedData = hash( data, secret )
signature = base64urlEncode( hashedData )
复制代码
是的JWT是经过不断的计算来进行校验的.
这里的性能问题, 指的是该结构带来的请求数据变多的问题. 在jwt的使用场景中, 全部的请求都须要完整带上jwt的数据. 因为payload这部分的数据仅仅是base64后的数据, 并无作任何处理. 因此, 若是在payload中增长过多的数据, 就会致使jwt的结构变大, 从而致使请求的效率下降.
若是把token存在redie或者mongodb中也是一个不错的选择. 咱们该如何作呢?
下面我以Laravel
迁移文件以下
$table->bigIncrements('id');
$table->integer('user_id');
$table->string('token', 191)->default('')->comment('token');
$table->integer('expiry_time')->default(0)->comment('到期时间');
$table->string('ua')->default('')->comment('浏览器');
$table->string('ip')->default('')->comment('使用者ip');
$table->timestamps();
复制代码
在经过登陆校验成功的时候生成Token
$token = md5(uniqid(md5(microtime(true)), true));
$token = sha1($token);
UserTokens::create([
'user_id' => $user->id,
'token' => $token,
'ip' => request()->ip(),
'expiry_time' => time() + 2 * 60 * 60,
'ua' => request()->userAgent()
]);
return $token;
复制代码
在须要的路由注入中间件拦截器
class Authenticate extends Controller
{
public function handle(Request $request, \Closure $next)
{
$Authorization = $request->header('Authorization');
if (!$Authorization) {
return response($this->error('请登陆', 40001));
}
$token = explode(' ', $Authorization);
$token = $token[1];
if ($this->validateToken($token)) {
return $this->validateToken($token);
}
return $next($request);
}
protected function validateToken($token)
{
$dbToken = UserTokens::where('token', $token)->first();
if ($dbToken->token != $token) {
return response($this->error('您的信息有误!', 40010));
} else if ($dbToken->expiry_time < time()) {
return response($this->error('token有效期到期', 40020));
} else if ($dbToken->ua != \request()->userAgent()) {
return response($this->error('您的信息有误!', 40010));
} else if ($dbToken->ip != \request()->ip()) {
return response($this->error('您的信息有误!', 40010));
} else {
return false;
}
}
}
复制代码
这种方式也是能够的.