新词:鉴权;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