认证机制JWT的应用
几种常见的认证机制
HTTP Basic Auth
最简单最基础的验证方式。
简单点说明就是每次请求API时都提供用户的username和password。
OAuth
无需将用户名和密码提供给第三方应用。
OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。
OAuth2.0的流程:
Cookie Auth
不支持跨域
Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上 来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改 cookie 的expire time使cookie在一定时间内有效;
Token Auth
支持跨域访问
更适用CDN
缺点 一旦颁发token就无法收回权限,但可以用后端逻辑来控制token的权限,比如利用有效期。
基于JWT的Token认证机制实现
JSON Web Token(JWT)是一个非常轻巧的规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。它是基于RFC 7519标准定义的一种可以安全传输的小巧和自包含的JSON对象。由于数据是使用数字签名的,所以是可信任的和安全的。JWT可以使用HMAC算法对secret进行加密或者使用RSA的公钥私钥对其进行签名。
验证流程如图:
基于PHP的实现:
demo代码地址
https://dev.tencent.com/u/xuxiao8/p/88/git
部分实现代码如下:
<?php
date_default_timezone_set("PRC"); //系统使用北京时间
require 'vendor/autoload.php';
use \Firebase\JWT\JWT;
define('KEY', '1gHuiop975cdashyex9Ud23ldsvm2Xq');
// php CROS 跨域解決方案
// header('content-type:application:json;charset=utf8');
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Methods:PUT,POST,GET,DELETE,OPTIONS');
header('Access-Control-Allow-Headers:x-requested-with,content-type,X-token');
$res['result'] = 'failed';
$action = isset($_GET['action']) ? $_GET['action'] : '';
if ($action == 'login') {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = htmlentities($_POST['user']);
$password = htmlentities($_POST['pass']);
if ($username == 'demo' && $password == 'demo') { //用户名和密码正确,则签发tokon
$nowtime = time();
$token = [
// 'iss' => 'http://192.168.1.214', //签发者 可选
// 'aud' => 'http://192.168.1.214', //jwt所面向的用户 可选
'iat' => $nowtime, //签发时间 可选
// 'nbf' => $nowtime + 10, //在什么时间之后该jwt才可用 可选
'exp' => $nowtime + 20, //过期时间20秒 可选
'data' => [
'userid' => 1,
'username' => $username
]
];
$jwt = JWT::encode($token, KEY);
$res['result'] = 'success';
$res['jwt'] = $jwt;
} else {
$res['msg'] = '用户名或密码错误!';
}
}
echo json_encode($res);
} else {
$jwt = isset($_SERVER['HTTP_X_TOKEN']) ? $_SERVER['HTTP_X_TOKEN'] : '';
if (empty($jwt)) {
$res['msg'] = 'You do not have permission to access.';
echo json_encode($res);
exit;
}
try {
JWT::$leeway = 60; //当前时间减去60,把时间留点余地
$decoded = JWT::decode($jwt, KEY, ['HS256']);
$arr = (array)$decoded;
if ($arr['exp'] < time()) {
$res['msg'] = '请重新登录';
} else {
$res['result'] = 'success';
$res['info'] = $arr;
}
} catch (\Firebase\JWT\SignatureInvalidException $e) {
//签名不正确
$res['msg'] = $e->getMessage();
} catch (\Firebase\JWT\BeforeValidException $e) {
// 签名在某个时间点之后才能用
$res['msg'] = $e->getMessage();
} catch (\Firebase\JWT\ExpiredException $e) {
// token过期
$res['msg'] = $e->getMessage();
} catch (Exception $e) {
//其他错误
$res['msg'] = $e->getMessage();
}
echo json_encode($res);
}