2024年最全TP6+JWT开发APP接口_tp6 session和jwt 交互(3),大厂架构师经验分享

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

* @return \think\response\Json
*/
private function jsonResponse($status, $message, $data, $httpCode = 200){

    $result = [
        'status' => $status, // 业务状态码
        'message' => $message,
        'result' => $data
    ];

    return json($result, $httpCode);
}

}


控制器调用



<?php /\*\* \* 老王 \* \*\*/ namespace app\api\controller; use app\BaseController; use app\common\lib\ResponseJson; class Test extends BaseController { public function index(){ ResponseJson::success(['test' => 'test']); ResponseJson::error(1, '未知错误'); } } ``` 2. 定义一个Trait, 用户代码复用, 在控制器引用后, 可以像调用该控制器类的方法一样 ``` <?php /\*\* \* 老王 \* \*\*/ namespace app\common\lib; use app\common\lib\error\ApiErrDesc; Trait ResponseJson{ /\*\* \* @param null $data \* @param int $httpCode \* @return \think\response\Json \*/ public function success($data = null, $httpCode = 200){ $status = ApiErrDesc::SUCCESS[0]; $message = ApiErrDesc::SUCCESS[1]; return $this->jsonResponse($status, $message, $data, $httpCode); } /\*\* \* @param $status \* @param $message \* @param null $data \* @param int $httpCode \* @return \think\response\Json \*/ public function error($status, $message, $data = null, $httpCode = 500){ return $this->jsonResponse($status, $message, $data, $httpCode); } /\*\* \* @param $status \* @param $message \* @param $data \* @param int $httpCode \* @return \think\response\Json \*/ private function jsonResponse($status, $message, $data, $httpCode = 200){ $result = [ 'status' => $status, // 业务状态码 'message' => $message, 'result' => $data ]; return json($result, $httpCode); } } ``` 控制器调用 ``` <?php /\*\* \* 老王 \* \*\*/ namespace app\api\controller; use app\BaseController; use app\common\lib\ResponseJson; class Test extends BaseController { use ResponseJson; public function index(){ $this->success(['test' => 'test']); $this->error(1, '未知错误'); } } ``` ##### 3. APP接口的鉴权 客户端要带着凭证来调用APP接口, 即有权限才可以调用 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623145933262.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MjYxMTMw,size_16,color_FFFFFF,t_70) ###### 3.1传统web的cookie session ![在这里插入图片描述](https://img-blog.csdnimg.cn/202006231501576.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MjYxMTMw,size_16,color_FFFFFF,t_70) web是基于浏览器, 可以采用该方式, 但是APP不是基于浏览器cooike和session的机制, 需要采用JWT ###### 3.2 JWT (Json Web Token) JWT原理即服务端认证以后, 生成一个JSON对象, 返回给客户端, 后续客户端所有的请求都必须带上这个JSON对象, 而服务端依靠这个JSON来认定用户身份 完整的JWT格式输出是以 . 分割的三段Base64编码 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200623151054464.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MjYxMTMw,size_16,color_FFFFFF,t_70) 组成 1. header, 通常包含两部分: 类型和采用的加密算法, header需要经过Base64Url编码后作为JWT的第一部分 2. payload, 载体, 包含了claim, iss: 签发者, exp: 过期时间戳, sub: 面向的用户, aud: 接收方, iat: 签发时间, 可以存放不敏感的信息, payload需要经过Base64Url编码后作为JWT的第二部分 3. signature, 创建签名, 使用编码后的header和payload以及一个密钥, 使用header中指定的签名算法进行签名, 生成的签名作为JWT的第三部分, 该签名是在服务端完成的, 客户端不知道密钥, 更安全 ###### 3.3 代码封装JWT的使用 JWT的官网 [JWT](https://bbs.csdn.net/topics/618658159) 找到PHP的库, 利用composer (PHP用来管理依赖关系的工具) 下载包文件[lcobucci/jwt](https://bbs.csdn.net/topics/618658159) 切换到项目目录执行composer ``` composer require lcobucci/jwt ``` 在app/common/auth文件下, 创建JWT封装类库文件 ``` <?php /\*\* \* 老王 \* \*\*/ namespace app\common\lib\auth; use Lcobucci\JWT\Builder; use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\ValidationData; /\*\* \* 单例模式 \* 一次请求中所有使用到jwt的地方都是一个用户 \* Class JwtAuth \* @package app\common\lib\auth \* 1. 接口鉴权 \* 2. 获取用户身份 \*/ class JwtAuth { /\*\* \* @var \*/ private $token; /\*\* \* @var \*/ private $decodeToken; /\*\* \* claim iss \* @var string \*/ private $iss = 'chao.com'; /\*\* \* claim aud \* @var string \*/ private $aud = 'tp6\_server\_app'; /\*\* \* 身份 uid \* @var string \*/ private $uid; /\*\* \* @var string \*/ private $secret = 'TP6&\*chao1992#$LJL\*&^&\*9089'; /\*\* \* @var null \*/ private static $instance = null; /\* \* 私有化 构造函数 \*/ private function \_\_construct() { } /\* \* \*/ private function \_\_clone() { // TODO: Implement \_\_clone() method. } /\*\* \* 单例模式 获取jwtAuth句柄 \* @return JwtAuth|null \*/ public static function getInstance() { if (is\_null(self::$instance)){ self::$instance = new self(); } return self::$instance; } /\*\* \* @param $uid \* @return $this \* 设置身份信息 \*/ public function setUid($uid){ $this->uid = $uid; return $this; } /\*\* \* @param $token \* 设置token \*/ public function setToken($token){ $this->token = $token; return $this; } /\*\* \* @param $token \*/ public function decode(){ if (!$this->decodeToken){ // 把字符串转成Token对象 $this->decodeToken = (new Parser())->parse((string)$this->token); $this->uid = $this->decodeToken->getClaim('uid'); } return $this->decodeToken; } /\*\* \* 校验signature, 判断token是否过期或者被篡改 \* @return bool \*/ public function verify(){ $signer = new Sha256(); $privateKey = new Key($this->secret); $result = $this->decode()->verify($signer, $privateKey); return $result; } /\*\* \* 校验参数 \* @return bool \*/ public function validate(){ $data = new ValidationData(); $data->setIssuer($this->iss); $data->setAudience($this->aud); return $this->decode()->validate($data); } /\*\* \* @return $this \*/ public function encode(){ $signer = new Sha256(); $privateKey = new Key($this->secret); $time = time(); // 颁发时间 $this->token = (new Builder()) ->withHeader('alg', 'HS256') ->issuedBy($this->iss) ->permittedFor($this->aud) ->issuedAt($time) ->expiresAt($time + 3600) // 过期时间 ->withClaim('uid', $this->uid) // 自定义参数 ->getToken($signer, $privateKey); return $this; } /\*\* \* 获取token \* @return string \*/ public function getToken(){ return (string)$this->token; } /\*\* \* @return string \*/ public function getUid(){ return $this->uid; } } ``` 控制器调用 ``` <?php /\*\* \* 老王 \* \*\*/ namespace app\api\controller; use app\BaseController; use app\common\lib\auth\JwtAuth; use app\common\lib\ResponseJson; class Test extends BaseController { use ResponseJson; public function index(){ // 获取jwtAuth的句柄 $jwtAuth = JwtAuth::getInstance(); $token = $jwtAuth->setUid(1)->encode()->getToken(); $this->success(['token' => $token]); } } ``` ###### 3.4 中间件 中间件主要用于拦截或者过滤应用的HTTP请求, 并进行必要的业务处理 1. 前置中间件: 请求时不会先去执行到控制器的某个方法, 而是先经过中间件, 然后再到某个控制器的某个方法去执行代码,如果中间件有拦截, 流程就会在中间件截断, 不会再往下执行方法, 而且获取不到控制器和方法, 因为会先执行中间件, 再执行控制器的方法 2. 后置中间件: 访问某个控制器的方法, 会先去执行方法里面的代码内容(不返回输出), 然后执行中间件的代码, 最后才是方法的输出返回, 如果中间件有拦截, 流程就会在中间件内截断, 但是方法内的代码也在前面执行了, 可以获取控制器和方法, 因为会先去执行这个控制器的方法, 再执行中间件 在app/api模块下, 新建middleware文件夹, 然后在该文件夹下创建类 ``` <?php /\*\* \* 老王 \* \*\*/ namespace app\api\middleware; use app\api\exception\ApiException; use app\common\lib\auth\JwtAuth; use app\common\lib\error\ApiErrDesc; use app\common\lib\ResponseJson; /\*\* \* Class CheckAuth \* @package app\api\middleware \* 中间件 \*/ class CheckAuth { /\*\* \* @param $request \* @param \Closure $next \*/ public function handle($request, \Closure $next){ $token = $request->header('token'); if ($token){ // 校验 $jwtAuth = JwtAuth::getInstance(); $jwtAuth->setToken($token); if ($jwtAuth->validate() && $jwtAuth->verify()){ return $next($request); }else{ throw new ApiException(ApiErrDesc::ERR\_LOGIN); } ![img](https://i-blog.csdnimg.cn/blog_migrate/0e9229d78ee2da9a07cf6c5dc3e9507d.png) ![img](https://img-blog.csdnimg.cn/img_convert/fe012bbc4b049ac8d4c252553de216e9.png) ![img](https://img-blog.csdnimg.cn/img_convert/b3493c82e4d4e432b42b4ee1117b2af5.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)** st); }else{ throw new ApiException(ApiErrDesc::ERR\_LOGIN); } [外链图片转存中...(img-KnSxASsn-1715720825512)] [外链图片转存中...(img-1HHT5TWa-1715720825512)] [外链图片转存中...(img-d3U4DWe9-1715720825513)] **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值