既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
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 KaTeX parse error: Undefined control sequence: \* at position 11: httpCode \̲*̲ @return \think…status, $message, $data = null, $httpCode = 500){
return $this->jsonResponse($status, $message, $data, $httpCode);
}
/\*\*
* @param $status
* @param $message
* @param $data
* @param int KaTeX parse error: Undefined control sequence: \* at position 11: httpCode \̲*̲ @return \think…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); } }else{ throw new ApiException(ApiErrDesc::ERR\_PARAMS); } } } ``` 注册中间件 在app/api模块下, 新建middleware.php文件 ``` <?php // 该模块下的中间件定义文件, 对该模块下的所有控制器都有效, 在middleware下写好中间件后, 需要在该文件下配置绑定 // 如果使得该中间件只针对某一个控制器有效, 可以借助路由来设置, 不需要在该文件下配置绑定, 直接在middleware下写好中间件然后通过路由绑定->middleware() return [ app\api\middleware\CheckAuth::class ]; ``` ##### 4. 业务逻辑异常处理 ###### 4.1 错误码 错误码是用来描述当前接口处理的结果, 是前后端共同的约束 格式: 1. code 错误码 2. msg 错误码对应的描述 一般以配置文件( config/status.php )或者类的常量来定义错误码, 统一管理便于维护 在app/common/lib文件夹下新建error, 并在该文件夹下创建类库 ``` <?php /\*\* \* 老王 \* \*\*/ namespace app\common\lib\error; /\*\* \* Class ApiErrDesc \* @package app\common\lib\error \* APi返回码类库 \*/ class ApiErrDesc { /\*\* \* Api通用错误码 \* error\_code < 1000 ![img](https://img-blog.csdnimg.cn/img_convert/eea20d7ee1969d21f31b6d65df1cc2dd.png) ![img](https://img-blog.csdnimg.cn/img_convert/747db59b247620480f2191208233017e.png) ![img](https://img-blog.csdnimg.cn/img_convert/5b1211fec9fc3e4223e43a39b614e8fc.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)** \* @package app\common\lib\error \* APi返回码类库 \*/ class ApiErrDesc { /\*\* \* Api通用错误码 \* error\_code < 1000 [外链图片转存中...(img-TNLxscQg-1715707771692)] [外链图片转存中...(img-zH09g9Tt-1715707771693)] [外链图片转存中...(img-w0eQ3Gd0-1715707771693)] **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**