分类 PHP知识 下的文章

认证机制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);
}