新词:鉴权;JWT
第1章 课程简介
- 课程内容
- 介绍什么是APP接口
- 详细介绍一个APP接口包含哪些关键模块(重难点)
- 介绍一个API实例
- 课程目标
- 了解APP接口的关键模块
- 学会构建一个APP接口的项目
- 开发环境(LNMP)
- PHP框架: Laravel
- 操作系统: MacOs
- Web服务器: Nginx
- APP接口介绍
- 什么是APP接口: 客户端与服务器端数据的交换
- 大部分APP接口是通过HTTP协议通信的
- HTTP通信三要素: URL通信地址,Method通信方式,Params通信内容
第2章 客户端参数传递(APP接口的输入)
- 客户端如何传递参数
- URL模式即GET
- RequestBody即POST
- post-form-url方式: RequestHeaders中Content-Type: application/x-www-form-urlencoded
- post-form-data方式: RequestHeaders中Content-Type: multipart/form-data;boundary=----WebKitFormBoundaryaUSyUoLPtL4bSqEk
- post-json方式: RequestHeaders中Content-Type: application/json;charset=UTF-8
- 服务端如何获取参数
- get方式使用$_GET
- post-form-url和post-form-data方式使用$_POST
- post-json方式使用file_get_contents("php://input") (p`hp://访问各个输入/输出流; php://input访问请求的原始数据的只读流)
第3章 服务端输出json介绍(APP接口的输出)
- JSON&XML简介
- XML是一种标记语言,设计宗旨是传输数据
- JSON是一种轻量级的数据交换格式
- APP接口输出格式三要素
- code: 错误码
- msg: 错误码对应的描述
- data: 接口返回的数据
- 示例
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接口授权
- 什么是APP接口的鉴权
- 谁有权限调用APP接口
- 客户端需要带着凭证来调用APP接口
- JWT原理
- 服务端认证以后,生成一个JSON对象,返回给用户
- 后续客户端所有的请求都会带上这个JSON对象
- 服务端依靠这个JSON来认定用户身份
- JWT组成(Header,Payload,Signature)
- 完整的JWT格式输出的是以点为分割的三段Base64编码
- Header eg: {'alg': "HS256",'typ': "JWT"}
- 通常包含两部分:类型和采用的加密算法
- header需要经过Base64Url编码后作为JWT的第一部分
- Payload eg: {'sub': "1233333",'name': "John Doe",'admin': true}
- payload包含了claim,三种类型reserved.public,private
- reserved这些claim是JWT预先定义的,不强制使用,常用的有:iss(签发者),exp(过期时间),sub(面向的用户),aud(接受方),iat(签发时间)
- payload需要经过Base64Url编码后作为JWT的第二部分
- Signature eg: HMACSHA256( base64UrlEncode(header)+'.'+base64UrlEncode(payload),secret )
- 创建签名使用编码后的header和payload以及一个密钥,使用header中指定的签名算法进行签名
- 在服务端进行加密保证安全性
- 实战
- 代码封装JWT的使用
- 服务端如何使用JWT下发token
- 服务端如何对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章 业务逻辑处理
- 错误码定义
- 错误码是用来描述当前接口处理的结果
- 错误码是前后端共同的一个约束
- 错误码的格式
- code错误码; msg错误码对应的描述
- 例: const SUCCESS = [0, 'Success'];
- 如何处理业务异常
- try...catch捕获异常
- 设置用户自定义的异常处理函数
- set_exception_handler: 设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler 调用后异常会中止。
- set_error_handler: 设置用户的函数 (error_handler) 来处理脚本中出现的错误。
- 例如,统一使用框架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章 接口信息开发
- 用户信息接口实战
- 数据库用户信息表设计
- 开发用户信息接口
- 使用Redis缓存加速用户信息接口
- 用户表设计
第7章 课程总结
- 核心模块
- API的输入输出
- API鉴权
- 异常处理
- 各个模块是如何协调工作的
来源:https://www.cnblogs.com/qiusanqi/p/12201494.html