php jwt登录验证

  1. require 'vendor/autoload.php';
    use \Firebase\JWT\JWT;
    define('KEY', '1gHuiop975cdashyex9Ud23ldsvm2Xq'); //密钥
    $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://www.helloweba.net', //签发者
                    'aud' => 'http://www.helloweba.net', //jwt所面向的用户
                    'iat' => $nowtime, //签发时间
                    'nbf' => $nowtime + 10, //在什么时间之后该jwt才可用
                    'exp' => $nowtime + 600, //过期时间-10min
                    '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;
            $decoded = JWT::decode($jwt, KEY, ['HS256']);
            $arr = (array)$decoded;
            if ($arr['exp'] < time()) {
                $res['msg'] = '请重新登录';
            } else {
                $res['result'] = 'success';
                $res['info'] = $arr;
            }
        } catch(Exception $e) {
            $res['msg'] = 'Token验证失败,请重新登录';
        }
        echo json_encode($res);

    使用composer安装php-jwt,接收到登录用户名和密码后,PHP验证用户名和密码是否正确(实际开发中应该结合数据库,从数据库里拿用户名和密码比对,本实例为了演示只做简单验证),如果用户名和密码准确无误,那么就签发token,在token中,我们可以定义token的签发者、过期时间等等,并返回给前端。注意在签发token时,我们需要定义一个密钥,这个密钥是一个私钥,实际应用中是保密的不可告诉别人。

composer require firebase/php-jwt

 

 

//自己封装

class Jwt
{
    //这个是头部
    private static $header=array(
        'alg' => 'HS256',//生成signature的算法
        'typ' => 'JWT'//类型
    );

    //使用HMAC生成信息摘要时所使用的秘钥
    private static $key = '123456';

    /**
     * 获取jwt token
     * @param array $payload jwt荷载
     * @return bool|string
     */
    public static function getToken(array $payload){
        if(is_array($payload)){
            $base64header = self::base64UrlEncode(json_encode(self::$header,JSON_UNESCAPED_UNICODE));
            $base64payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
            $base64signature = self::signature($base64header . '.' . $base64payload, self::$key, self::$header['alg']);
            return $token = $base64header . '.' . $base64payload . '.' . $base64signature;
        }else{
            return false;
        }
    }

    /**
     * 验证token是否有效,默认值验证exp时间
     * @param string $token 需要验证的token
     * @return bool|mixed 如果正确,那么,将返回数组$payload
     */
    public static function verifyToken(string $token){
        $tokens = explode('.', $token);
        if (count($tokens) != 3){
            return false;
        }
        list($base64header, $base64payload, $sign) = $tokens;

        //获取header部分
        $base64decodeheader = json_decode(self::base64UrlDecode($base64header),true);
        if (empty($base64decodeheader['alg'])){
            return false;
        }

        //签名验证,就是将现成的$base64header和$base64payload重新加密一遍,看是不是等于$sing
        $calc_sign = self::signature(
            $base64header . '.' . $base64payload,
            self::$key,
            $base64decodeheader['alg'],
            );
        if ($calc_sign != $sign){
            return false;
        }

        //获得payload
        $payload = json_decode(self::base64UrlDecode($base64payload),true);

        //核对过期时间是不是小于现在的时间,如果是,那就返回false
        if (isset($payload['exp']) && $payload['exp'] < time()){
            return false;
        }

        return $payload;
    }

    /**
     * 首先用base64_encode编码,然后换掉+/=这3个符号
     * 为什么不直接用urlEncode?
     * 我觉得可能是为了减少运算吧,反正就这3个符号,没有更多。
     * @param string $input 需要编码的字符串
     * @return string 编码后的字符串
     */
    private static function base64UrlEncode(string $input){
        return str_replace('=','',strtr(base64_encode($input),'+/','-_'));
    }

    /**
     * 解码由base64UrlEncode()编码的字符串
     * @param string $input
     * @return bool|string 解码后的字符串
     */
    private static function base64UrlDecode(string $input){
        $remainder = strlen($input) % 4;
        if ($remainder) {
            $addlen = 4 - $remainder;
            $input .= str_repeat('=', $addlen); //差了几个=就补上几个等号
        }
        return base64_decode(strtr($input, '-_', '+/'));
    }

    /**
     * HMACSHA256签名
     * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
     * @param string $key 秘钥
     * @param string $alg 算法
     * @return string 返回签名的编码后的字符串
     */
    private static function signature(string $input, string $key, string $alg = 'HS256'){
        $alg_config = array(
            'HS256' => 'sha256'
        );
        $signature = hash_hmac($alg_config[$alg], $input, $key, true);
        return self::base64UrlEncode($signature);
    }
}
public function testToken(){
    $payload = [
        'exp' => time() + 9000,
        'name' => 'user',
        'jti' => '11111233'
    ];
    return $token = Jwt::getToken($payload);
}

public function testToken2(){
    $token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjUwMTk2NzIsIm5hbWUiOiLmsZ_niofniociLCJqdGkiOiIxMTExMTIzMyJ9.mgSMwnpHQiIlBYNGTphAsYWc2pTiygj1AhmQU_p1OBw';
    $payload = Jwt::verifyToken($token);
    dump($payload);
}

 

posted @ 2023-03-18 16:35  垖垏尐  阅读(39)  评论(0编辑  收藏  举报