PHP开发APP接口

≯℡__Kan透↙ 提交于 2020-01-16 16:09:44
新词:鉴权;JWT
第1章 课程简介
  1. 课程内容
    1. 介绍什么是APP接口
    2. 详细介绍一个APP接口包含哪些关键模块(重难点)
    3. 介绍一个API实例
  2. 课程目标
    1. 了解APP接口的关键模块
    2. 学会构建一个APP接口的项目
  3. 开发环境(LNMP)
    1. PHP框架: Laravel
    2. 操作系统: MacOs
    3. Web服务器: Nginx
  4.  APP接口介绍
    1. 什么是APP接口: 客户端与服务器端数据的交换
    2. 大部分APP接口是通过HTTP协议通信的
    3. HTTP通信三要素: URL通信地址,Method通信方式,Params通信内容
 
第2章 客户端参数传递(APP接口的输入)
  1. 客户端如何传递参数
    1. URL模式即GET
    2. RequestBody即POST
      1. post-form-url方式: RequestHeaders中Content-Type: application/x-www-form-urlencoded
      2. post-form-data方式: RequestHeaders中Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryaUSyUoLPtL4bSqEk
      3. post-json方式: RequestHeaders中Content-Type: application/json;charset=UTF-8
  2. 服务端如何获取参数
    1. get方式使用$_GET
    2. post-form-url和post-form-data方式使用$_POST
    3. post-json方式使用file_get_contents("php://input") (p`hp://访问各个输入/输出流; php://input访问请求的原始数据的只读流)
 
第3章 服务端输出json介绍(APP接口的输出)
  1. JSON&XML简介
    1. XML是一种标记语言,设计宗旨是传输数据
    2. JSON是一种轻量级的数据交换格式
  2. APP接口输出格式三要素
    1. code: 错误码
    2. msg: 错误码对应的描述
    3. data: 接口返回的数据
  3. 示例
 1 //trait是为类似PHP的单继承语言而准备的一种代码复用的机制
 2 //别的类中use trait型,
 3 
 4 trait ResponseJson{
 5     //当App接口出现业务异常时的返回
 6     public function jsonData($code,$message,$data = []){
 7         return $this->jsonResponse($code,$message,$data);
 8     }
 9     //App接口请求成功时返回
10     public function jsonSuccessData($data = []){
11         return $this->jsonResponse(0,'Success',$data);
12     }
13     //返回一个json
14     private function jsonResponse($code, $message, $data){
15         $content = [
16             'code'=>$code,
17             'msg'=>$message,
18             'data'=>$data
19         ];
20         return json_encode($content);
21     }
22 }
23 
24 //trait的使用
25 class Controller extends BaseController{
26     use ResponseJson;
27     public function index(){
28         return $this->jsonSuccessData(['hello'=>'123');
29     }
30 }

 

 
第4章 APP接口授权
  1. 什么是APP接口的鉴权
    1. 谁有权限调用APP接口
    2. 客户端需要带着凭证来调用APP接口
  2. JWT原理
    1. 服务端认证以后,生成一个JSON对象,返回给用户
    2. 后续客户端所有的请求都会带上这个JSON对象
    3. 服务端依靠这个JSON来认定用户身份
  3. JWT组成(Header,Payload,Signature)
    1. 完整的JWT格式输出的是以点为分割的三段Base64编码
    2. Header eg: {'alg': "HS256",'typ': "JWT"}
      1. 通常包含两部分:类型和采用的加密算法
      2. header需要经过Base64Url编码后作为JWT的第一部分
    3. Payload eg: {'sub': "1233333",'name': "John Doe",'admin': true}
      1. payload包含了claim,三种类型reserved.public,private
      2. reserved这些claim是JWT预先定义的,不强制使用,常用的有:iss(签发者),exp(过期时间),sub(面向的用户),aud(接受方),iat(签发时间)
      3. payload需要经过Base64Url编码后作为JWT的第二部分
    4. Signature eg: HMACSHA256( base64UrlEncode(header)+'.'+base64UrlEncode(payload),secret )
      1. 创建签名使用编码后的header和payload以及一个密钥,使用header中指定的签名算法进行签名
      2. 在服务端进行加密保证安全性
  4. 实战
    1. 代码封装JWT的使用
    2. 服务端如何使用JWT下发token
    3. 服务端如何对token鉴权
  1 // App/Common/Auth/JwtAuth.php
  2 namespace App\Common\Auth;
  3 //单例 一次请求中所有出现使用jwt的地方都是一个用户
  4 class JwtAuth{
  5     //jwt token
  6     private $token;
  7     private $decodeToken;
  8     
  9     private $iss = 'api.test.com';
 10     private $aud = 'imooc_server_app';
 11     private $uid;
 12     private $secrect = 'wwwqeqweqwe';//加密规则
 13     
 14     //jwtAuth句柄
 15     private static $instance;
 16     //获取jwtAuth句柄
 17     public static function getInstance(){
 18         if(is_null(self::$instance)){
 19             self::$instance = new self();
 20         }
 21         return self::$instance;
 22     }
 23     //私有化构造函数
 24     private function __construct(){}
 25     //私有化clone函数
 26     private function __clone(){}
 27     
 28     public function getToken(){
 29         return (string)$this->token;
 30     }
 31     public function setToken($token){
 32         $this->token = $token;
 33         return $this;
 34     }
 35     public function setUid($uid){
 36          $this->uid = $uid;
 37          return $this;
 38     }
 39     
 40     //编码jwt token
 41     public function encode(){
 42         $time = time();
 43         $this->token = (new Builder())->setHeader('alg','HS256')
 44             ->setIssuer($this->iss)
 45             ->setAudience($this->aud)
 46             ->setIssuedAt($time)
 47             ->setExpiration($time + 3600)
 48             ->set('uid', $this->uid)
 49             ->sign(new Sha256(), $this->secrect)
 50             ->getToken();
 51         return $this;
 52     }
 53     
 54     //使用parse将token字符串解析为token对象
 55     public function decode(){
 56         if(!$this->decodeToken){
 57             $this->decodeToken = (new Parser())->parse((string)$this->token);
 58             $this->uid = $this->decodeToken->getClaim('uid');
 59         }
 60         return $this->decodeToken;
 61     }
 62     public function verify(){
 63         $result = $this->decode()->verify(new sha256(),$this->sercret);
 64         return $result;
 65     }
 66     public function validate(){
 67         $data = new ValidationData();
 68         $data->setIssuer($this->iss);
 69         $data->setAudience($this->aud);
 70         
 71         return $this->decode()->validate($data);
 72     }
 73 }
 74 
 75 //JWT的使用
 76 class JWTLoginController extends BaseController{
 77     use ResponseJson;
 78     public function login(Request $request){
 79         $username = $request->input('user_name');
 80         $password = $request->input('pass_word');
 81         
 82         //去数据库或者缓存中验证该用户...
 83         
 84         $jwtAuth = JwtAuth::getInstance();
 85         $token = $jwtAuth->setUid(1)->encode()->getToken();
 86         return $this->jsonSuccessData([
 87             'token'=>$token,
 88         ])
 89     }
 90 }
 91 
 92 //使用中间件验证token
 93 class JwtMiddleware{
 94     use ResponseJson;
 95     public function handle($request, Closure $next){
 96         $token = $request->input('token');
 97         if($token){
 98             $jwtAuth = JwtAuth::getInstance();
 99             $jwtAuth->setToken($token);
100             
101             if($jwtAuth->validate() && $jwtAuth->verify()){
102                 return $next($request);
103             }else{
104                 return $this->jsonData(1,'登录过期');
105             }
106         }else{
107             return $this->jsonData(2,'参数错误');
108         }
109     }
110 }

 

 
第5章 业务逻辑处理
  1. 错误码定义
    1. 错误码是用来描述当前接口处理的结果
    2. 错误码是前后端共同的一个约束
  2. 错误码的格式
    1. code错误码; msg错误码对应的描述
    2. 例: const SUCCESS = [0, 'Success'];
  3. 如何处理业务异常
    1. try...catch捕获异常
    2. 设置用户自定义的异常处理函数
      1. set_exception_handler: 设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler 调用后异常会中止。
      2. set_error_handler: 设置用户的函数 (error_handler) 来处理脚本中出现的错误。
  4. 例如,统一使用框架Handler来处理接口异常返回
 1 //ApiErrDesc.php
 2 namespace App\Common\Err;
 3 
 4 class ApiErrDesc{
 5     //API通用错误码 error_code < 1000
 6     const SUCCESS = [0, 'Success'];
 7     const UNKNOWN_ERR = [1, '未知错误'];
 8     const ERR_URL = [2, '访问接口不存在'];
 9     
10     const ERR_PARAMS = [100, '参数错误'];
11     
12     //error_code 1001-1100 用户登录相关的错误码
13     const ERR_PASSWORD = [1001, '密码错误'];
14     const ERR_TOKEN = [1002,'登录过期'];
15 }
16 
17 
18 
19 
20 //示例代码test_exception.php
21 ///传统try catch/////
22 try{
23     throw new \Exception('try catch exception');
24 }catch (\Exception $e){
25     echo $e->getMessage().PHP_EOL;
26 }
27 ///set_exception_handler/////
28 function customExceptionHandle($e){
29     echo $e->getMessage().PHP_EOL;
30 }
31 
32 set_exception_handler('customExceptionHandle');//使用set_exception_handler设置自定义函数
33 throw new \Exception('custom exception');
34 
35 //laravel框架使用App\Exception\Handler.php的render方法处理未被trycatch的异常
36 class Handler{
37     use ResponseJson;
38     public function render($request, Exception $exception){
39         //return parent::render($request, $exception);
40         if($exception instanceof ApiException){
41             $code = $exception->getCode();
42             $message = $exception->getMessage();
43         }else{
44             $code = $exception->getCode();
45             if(!$code || $code < 0){
46                 $code = ApiErrDesc::UNKNOWN_ERR[0];
47             }
48             $message = $exception->getMessage() ? : ApiErrDesc::UNKNOWN_ERR[1];
49         }
50         return $this->jsonData($code,$message);
51     }
52 }
53 
54 
55 
56 //定义自己的ApiException.php
57 namespace App\Exception;
58 use Throwable;
59 
60 class ApiException extends \RuntimeException{
61     public function __construct(array $apiErrConst, Throwable $previous = null){
62         $code = $apiErrConst[0];
63         $msg = $apiErrConst[1];
64         parent::__construct($message,$code,$previous);
65     }
66 }
67 
68 //使用中间件验证token,结合异常处理
69 namespace App\Http\Middleware
70 
71 class JwtMiddleware{
72     use ResponseJson;
73     public function handle($request, Closure $next){
74         $token = $request->input('token');
75         if($token){
76             $jwtAuth = JwtAuth::getInstance();
77             $jwtAuth->setToken($token);
78             
79             if($jwtAuth->validate() && $jwtAuth->verify()){
80                 return $next($request);
81             }else{
82                 //return $this->jsonData(1,'登录过期');
83                 //return $this->jsonData(ApiErrDesc::ERR_PASSWORD[0], ApiErrDesc::ERR_PASSWORD[1]);
84                 throw new ApiException(ApiErrDesc::ERR_TOKEN);
85             }
86         }else{
87             //return $this->jsonData(2,'参数错误');
88             //return $this->jsonData(ApiErrDesc::ERR_PARAMS[0], ApiErrDesc::ERR_PARAMS[1]);
89             throw new ApiException(ApiErrDesc::ERR_PARAMS);
90         }
91     }
92 }

 

 
第6章 接口信息开发
  1. 用户信息接口实战
    1. 数据库用户信息表设计
    2. 开发用户信息接口
    3. 使用Redis缓存加速用户信息接口
  2. 用户表设计
 
第7章 课程总结
  1. 核心模块
    1. API的输入输出
    2. API鉴权
    3. 异常处理
  2. 各个模块是如何协调工作的
 
 
 
 
 
 
 
 
 
 
 
 
 
 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!