thinkphp6集成JWT
1.什么是JWT
在介绍JWT之前,我们先来回顾一下利用token进行用户身份验证的流程:
客户端使用用户名和密码请求登录
服务端收到请求,验证用户名和密码
验证成功后,服务端会签发一个token,再把这个token返回给客户端
客户端收到token后可以把它存储起来,比如放到cookie中
客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带
服务端收到请求,然后去验证客户端请求里面带着的token,如果验证成功,就向客户端返回请求数据
这种基于token的认证方式相比传统的session认证方式更节约服务器资源,并且对移动端和分布式更加友好。其优点如下:
2.相比传统token验证的优点
支持跨域访问:cookie是无法跨域的,而token由于没有用到cookie(前提是将token放到请求头中),所以跨域后不会存在信息丢失问题
无状态:token机制在服务端不需要存储session信息,因为token自身包含了所有登录用户的信息,所以可以减轻服务端压力
更适用CDN:可以通过内容分发网络请求服务端的所有资料
更适用于移动端:当客户端是非浏览器平台时,cookie是不被支持的,此时采用token认证方式会简单很多
无需考虑CSRF:由于不再依赖cookie,所以采用token认证方式不会发生CSRF,所以也就无需考虑CSRF的防御
3.废话不多说,直接上代码。
第一步,安装thinkphp6
composer create-project topthink/think mythink(项目名字)
第二步,安装多应用,迟早要用上的,索性安装上
composer require topthink/think-multi-app
第三步,安装JWT扩展。
composer require firebase/php-jwt
4.测试上代码。
php think build admin(建后台应用)
php think build api (建立前台应用)
在应用控制器下面新建公用Controller.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | <?php declare (strict_types = 1); namespace app\admin\controller; use app\BaseController; use think\response\Json; class Controller extends BaseController { /** * 初始化 */ public function initialize() { //拦截验证 //do something } /** * 返回封装后的 API 数据到客户端 */ protected function renderData(int $status = null, string $message = '' , array $data = []): Json { is_null ( $status ) && $status = config( 'status.success' ); return json(compact( 'status' , 'message' , 'data' )); } /** * 返回操作成功json * @param array|string $data * @param string $message * @return Json */ protected function renderSuccess( $data = [], string $message = 'success' ): Json { if ( is_string ( $data )) { $message = $data ; $data = []; } return $this ->renderData(200, $message , $data ); } /** * 返回操作失败json * @param string $message * @param array $data * @return Json */ protected function renderError(string $message = 'error' , array $data = []): Json { return $this ->renderData(500, $message , $data ); } /** * 获取post数据 (数组) * @param $key * @return mixed */ protected function postData( $key = null) { return $this ->request->post( empty ( $key ) ? '' : "{$key}/a" ); } /** * 获取post数据 (数组) * @param string $key * @return mixed */ protected function postForm(string $key = 'form' ) { return $this ->postData( $key ); } /** * 获取post数据 (数组) * @param $key * @return mixed */ protected function getData( $key = null) { return $this ->request->get( is_null ( $key ) ? '' : $key ); } } |
然后再加上 jwt 的公用方法,在commen.php里面写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <?php // 应用公共文件 use Firebase\JWT\BeforeValidException; use Firebase\JWT\ExpiredException; use Firebase\JWT\JWT; use Firebase\JWT\Key; use Firebase\JWT\SignatureInvalidException; const JWT_TTL = 7200; /**生成验签 * @param $data * @return string */ function signToken( $data ) :string { $key = 'LAL@lc!' ; //这里是自定义的一个随机字串,应该写在config文件中的,解密时也会用,相当于加密中常用的 盐-salt $token = array ( "iss" => $key , //签发者 可以为空 "aud" => '' , //面象的用户,可以为空 "iat" => time(), //签发时间 "nbf" => time() + 3, //在什么时候jwt开始生效 (这里表示生成100秒后才生效) "exp" => time() + JWT_TTL, //token 过期时间 "data" => $data //记录的userid的信息,这里是自已添加上去的,如果有其它信息,可以再添加数组的键值对 ); return JWT::encode( $token , $key , "HS384" ); //根据参数生成了token,可选:HS256、HS384、HS512、RS256、ES256等 } /**验证token * @param $token * @return array|int[] */ function checkToken( $token ) : array { $key = 'LAL@lc!' ; $status = [ 'code' => 500]; try { JWT:: $leeway = 60; //当前时间减去60,把时间留点余地 $decoded = JWT::decode( $token , new Key( $key , 'HS384' )); //同上的方式,这里要和签发的时候对应 $arr = ( array ) $decoded ; $res [ 'code' ] = 200; $res [ 'data' ] = $arr [ 'data' ]; $res [ 'data' ] = json_decode(json_encode( $res [ 'data' ]), true); //将stdObj类型转换为array return $res ; } catch (SignatureInvalidException $e ) { //签名不正确 $status [ 'msg' ] = "签名不正确" ; return $status ; } catch (BeforeValidException $e ) { // 签名在某个时间点之后才能用 $status [ 'msg' ] = "token失效" ; return $status ; } catch (ExpiredException $e ) { // token过期 $status [ 'msg' ] = "token失效" ; return $status ; } catch (Exception $e ) { //其他错误 $status [ 'msg' ] = "未知错误" ; return $status ; } } |
准备工作做完了,我们按照平时的习惯写接口,比如我们在admin应用的controller 下面新建Index.php,然后开始测试JWT。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?php declare (strict_types = 1); namespace app\admin\controller; use think\response\Json; class Index extends Controller { public function index():Json { $data = [ 'id' => 1001, 'name' => "吴俊峰" ]; $data [ 'token' ] = signToken( $data ); return $this ->renderSuccess( $data ); } public function check():Json { $token = $this ->request->header( 'token' ); $user_info = checkToken( $token ); if ( $user_info [ 'code' ] != 200){ return $this ->renderError( 'token验证失败' ); } return $this ->renderSuccess( $user_info , '验证成功' ); } } |
我们先访问 index方法接口,如下,
我们再用得到的token去访问其他接口,
怎么样,是不是很简单?有错误之处,请大家斧正!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具