JWT生成Token做登录校验
一、JWT的优点
1、服务端不需要保存传统会话信息,没有跨域传输问题,减小服务器开销。
2、jwt构成简单,占用很少的字节,便于传输。
3、json格式通用,不同语言之间都可以使用。
二、使用JWT进行用户登录鉴权的流程
① 用户使用用户名密码来请求服务器
② 服务器进行验证用户的信息
③ 服务器通过验证发送给用户一个token
④ 客户端存储token,并在每次请求时附送上这个token值
⑤ 服务端验证token值,并返回数据
三、php-jwt库下载地址
1、通过composer下载:
composer require firebase/php-jwt
2、github下载地址:https://github.com/firebase/php-jwt
3、百度云下载地址:https://pan.baidu.com/s/1lpyz8oKf_CM-kOi7MGVoPg
提取码:wyq0
三、简单示例
1、登录页面代码:login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="showpage"> <div class="form-group"> <label for="username">用户名</label> <input type="text" class="form-control" id="username" placeholder="请输入用户名"> </div> <div class="form-group"> <label for="password">密码</label> <input type="password" class="form-control" id="password" placeholder="请输入密码"> </div> <button type="submit" id="sub-btn" class="btn btn-default">登录</button> <br/> <p class="bg-warning" style="padding: 10px;">演示用户名和密码都是<code>demo</code>。</p> </div> </body> </html> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script> $('#sub-btn').on('click',function (e) { $.ajax({ type: 'post', url: './user.php?action=login', data: { username:$('#username').val(), password:$('#password').val(), }, dataType:'json', success: function (data, status, xhr) { alert(data.msg); if(data.code==200){ //将jwt存储到本地 var jwt = xhr.getResponseHeader('Authorization'); localStorage.setItem("jwt", jwt); //跳转登录成功的页面 window.location.href="./user.html"; } } }); }); </script>
2、登录成功后页面代码:user.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你已成功登陆</h3> </body> </html> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script> $.ajax({ type: 'post', url: './user.php', headers: { 'Authorization': localStorage.getItem("jwt") }, data: {}, async: true, dataType: 'json', success: function (data, status, xhr) { if(data.code!=200){ //jwt验证失败 } //如果响应头接收到了Authorization,则将本地jwt更新 if (xhr.getResponseHeader('Authorization')) { localStorage.setItem("jwt", jwt); } }, error: function () { alert('error'); } }); </script>
3、后端PHP代码:user.php
<?php /* 使用composer安装php-jwt,接收到登录用户名和密码后,PHP验证用户名和密码是否正确 (实际开发中应该结合数据库,从数据库里拿用户名和密码比对,本实例为了演示只做简单验证), 如果用户名和密码准确无误,那么就签发token,在token中,我们可以定义token的签发者 、过期时间等等,并返回给前端。注意在签发token时,我们需要定义一个密钥,这个密钥是一个私钥, 实际应用中是保密的不可告诉别人。 * */ require_once './php-jwt-master/src/JWT.php'; use \Firebase\JWT\JWT; define('KEY', '1gHuiop975cdashyex9Ud23ldsvm2Xq'); //密钥 $action = isset($_GET['action']) ? $_GET['action'] : ''; if ($action == 'login') { if ($_SERVER['REQUEST_METHOD'] == 'POST') { $username = htmlentities($_POST['username']); $password = htmlentities($_POST['password']); $data = ['userid' => 1, 'username' => $username]; if ($username == 'demo' && $password == 'demo') { //用户名和密码正确,则签发tokon $nowtime = time(); $token = [ 'iss' => 'http://www.helloweba.net', //签发者 'aud' => $_SERVER['REMOTE_ADDR'], //jwt所面向的用户 'iat' => $nowtime, //签发时间 'exp' => $nowtime + 600, //过期时间-10min 'data' => $data ]; $jwt = JWT::encode($token, KEY); header("Authorization:$jwt"); $res = array('code' => 200, 'msg' => '登录成功', 'data' => $data); } else { $res = array('code' => 300, 'msg' => '登录失败'); } } die(json_encode($res)); } else { $jwt = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : ''; if (empty($jwt)) { $res = array('code' => 301, 'msg' => 'You do not have permission to access.'); die(json_encode($res)); } try { JWT::$leeway = 60;//当前时间减去60,把时间留点余地 $token = JWT::decode($jwt, KEY, ['HS256']); //HS256方式,这里要和签发的时候对应 } catch (Exception $exception) { $res = array('code' => 302, 'msg' => $exception->getMessage()); die(json_encode($res)); } // 疑似窃取用户Token攻击行为:请求的客户端ip已经改变, 拒绝请求 if ($token->aud !== $_SERVER['REMOTE_ADDR']) { $res['msg'] = "请求的客户端ip已经改变, 拒绝请求"; } // token过了有效期, 但是在回旋时间内, 静默更新用户token if ($token->exp < time()) { $token = (array)$token; $nowtime = time(); $token['iat'] = $nowtime; //签发时间 $token['exp'] = $nowtime + 600; //过期时间-10min; $jwt = JWT::encode($token, KEY); header("Authorization:$jwt"); } $res = array('code' => 200, 'msg' => 'success'); die(json_encode($res)); }
=======================================
由于本人水平有限,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论哦。你也可以关注我,一起学习哦!