php jwt登录验证
-
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); }