Files
phalapi-pro/public/wiki/2x-how-to-dev-api.md
2022-03-21 11:16:38 +08:00

366 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 如何开发接口
使用PhalApi专业版开发接口非常简单大致流程如下。
## 目录结构
PhalApi Pro版的目录结构如下
```
./
├── README.md # 简介
├── bin # 脚本目录
├── config # 配置目录
│   ├── app.php # 应用配置
│   ├── dbs.php # 数据库配置
│   ├── di.php # 依赖服务配置
│   └── sys.php #系统配置
├── data # 数据库
│   └── phalapi_pro.sql # 数据库安装时的文件
├── language # 翻译包
├── pro_admin # 管理后台的前端源代码基于iview-admin
├── pro_platform # 开放平台的前端源代码基于iview-admin
├── public # 对外访问的目录
│   ├── admin # 管理后台访问入口相当于pro_admin打包构建后的dist目录
│   ├── api # 接口访问入口内分前台API和后台API
│   ├── docs # 离线生成的HTML接口文档
│   ├── docs.php # 在线版接口文档访问入口
│   ├── index.php
│   ├── init.php # 全局初始化文件
│   ├── install # 安装向导(成功安装后建议删除此目录)
│   ├── platform # 开放平台访问入口相当于pro_platform打包构建后的dist目录
│   ├── static # 静态资源
│   ├── uploads # 上传目录(需要有写入权限)
│   └── wiki # 技术文档
├── runtime # 运行目录
│   ├── _install.lock # 安装锁定文件
│   ├── cache # 文件缓存
│   └── log # 文件日志
├── sdk # SDK包
├── src # 项目源代码,非常重要
│   ├── admin # 后台接口源代码遵循ADM模式
│   ├── app # 开放平台接口源代码遵循ADM模式
│   ├── base # 基础包源代码放置底层公共的代码不对外直接提供接口即不提供Api层
│   ├── platform # 开放平台接口源代码遵循ADM模式
│   ├── task # 计划任务接口源代码遵循ADM模式
│   └── view # 页面模板目录(如接口文档)
├── tests # 单元测试
└── vendor # composer包不需要手动修改通过composer install/update可进行安装和更新
```
PHP代码层次结构如下
![](http://cdn7.okayapi.com/yesyesapi_20200416113656_6c74c2813bed5ce7f552c5ed2a1007cc.png)
## 编写Api接口层
如果需要编写开放接口,可以在./src/app/Api目录下新增一个PHP文件类名和文件名一样需要区分大小写。并继承App\Common\Api基类即可。
例如开放接口的Hello World示例接口文件是./src/app/Api/HelloWorld.php类名是App\Api\HelloWorld对接的接口服务名称是App.HelloWorld.Say。
```php
<?php
namespace App\Api;
use App\Common\Api;
/**
* Hello World示例
*/
class HelloWorld extends Api {
// 接口参数配置
public function getRules() {
return array(
'say' => array(
'nickname' => array('name' => 'nickname', 'desc' => '昵称'),
),
);
}
/**
* 示例
* @desc 第一个前台接口示例
*/
public function say() {
$nickname = $this->nickname;
return array('content' => 'Hello world!');
}
}
```
保存后,访问接口文档列表,可以看到以下新接口:
![](http://cdn7.okayapi.com/yesyesapi_20191231095424_6cdab6e1dbac43fd95726fa2033412e0.png)
同时在接口详情文档可以查看到相应的详细接口文档:
![](http://cdn7.okayapi.com/yesyesapi_20191231100511_05d90cae0288de0649d1476772142a15.png)
如果需要编写后台接口,则需要放置在./src/admin/Api目录下并继承Admin\Common\Api基类。其他开发要求类似。
> 温馨提示以下方法是系统保留的函数名不以用于接口函数名称否则会影响接口正常运行。系统保留接口函数名称有tryToGetUid()、checkUserLogin()、tryToGetAppKey()、checkAppOnline()、getCurContext()、init()、createMemberValue()、getApiRules()、getApiCommonRules()、getRules()、filterCheck()、userCheck()、isServiceWhitelist()、equalOrIngore()。
## 如何取消接口令牌验证?
默认情况下,前台接口需要进行```access_token```令牌验证,以保护接口不被非法请求。如果不需要对指定的接口进行验证,可以在配置文件./config/app.php中的service_whitelist白名单中添加接口。例如上面的HelloWorld接口不需要接口验证可以在最后追加配置
```php
'service_whitelist' => array(
'Site.Index',
'HelloWorld.Say', // 追加Hello World示例白名单
),
```
接口白名单配置,会取消过滤器,不进行任何校验和判断,此时不会相应调整应用的接口权限。如果需要让接口权限在界面上显示保持一致,可以配置接口权限规则。
> 温馨提示:配置接口白名单,开放平台和管理后台的接口权限显示不会影响。
## 如何取消接口权限判断?
+ 如何取消全部接口权限判断?
可以修改./config/app.php里面的default_app_api_rigths_is_allow配置项为true即可让开放接口默认拥有权限相当于取消全部接口权限判断。
+ 如何取消某个接口类的接口权限判断?
在你的接口具体子类中,重载```\App\Common\Api::userCheck()```方法,不进行任何操作即可。
```php
/**
* 平台接口基类
*/
class Api extends \App\Common\Api {
/**
* 进行接口权限判断
* @throws BadRequestException
*/
protected function userCheck() {
// 不需要
}
}
```
> 温馨提示:通过代码取消接口权限判断,开放平台和管理后台的接口权限显示不会影响。
+ 如何取消一个接口的接口权限判断?
在你的接口具体子类中,重载```\App\Common\Api::userCheckActionWhitelist()```方法,返回不需要进行接口权限判断的接口白名单。
```php
<?php
namespace App\Api;
use App\Common\Api;
/**
* Hello World示例
*/
class HelloWorld extends Api {
protected function userCheckActionWhitelist() {
return array('hiApp', 'hiMember');
}
}
```
> 温馨提示:通过代码取消接口权限判断,开放平台和管理后台的接口权限显示不会影响。
## 如何获取当前上下文信息?
如何获取当前上下文、登录会员ID和app_key
在App\Common\Api接口基类中已经封装了针对于当前上下文、登录会员ID和app_key等接口方便项目快速开发。
以下是使用代码和相关说明。
```php
class HelloWorld extends Api {
public function say() {
// 获取会员ID未登录时异常返回
$uid = $this->tryToGetUid();
// 获取会员ID未登录时返回0
$uid = $this->tryToGetUid(false);
// 检测会员是否已登录,未登录时异常返回
$this->checkUserLogin();
// 获取app_key未指定时异常返回
$appKey = $this->tryToGetAppKey();
// 获取app_key未指定时返回空字符串
$appKey = $this->tryToGetAppKey(false);
// 检测是否已指定app_key
$this->checkAppOnline();
// 获取当前上下文
$context = $this->getCurContext();
var_dump($context->getUid()); // 会员ID
var_dump($context->getAppKey()); // app_key
}
}
````
## 如何隐藏access_token参数
如果不需要在接口文档上显示```access_token```参数可以在接口参数规则里这样配置设置is_doc_hide为true即可
```php
class HelloWorld extends Api {
public function getRules() {
return array(
'say' => array(
'accessToken' => array('name' => 'access_token', 'is_doc_hide' => true),
),
)
}
}
```
## 编写Domain领域层
Domain领域层主要用于封装复杂的业务逻辑、规则和算法。此部分PHP代码放置在./src/app/Domain目录下。此部分根据不同项目的业务需求具体开发即可。
## 编写Model数据层
Model数据层主要用于操作MySQL数据库全部的Model子类可继承Base\Model\Base基类此基类封装了很多实用的方法和接口极大减少了数据库封装的代码。例如对应配置表的配置Model类代码如下
```php
<?php
namespace App\Model;
class Config extends Base {
}
```
对应源代码文件是:./src/app/Model/Config.php。
在继承```Base\Model\Base```数据库基类后,可以很方便进行数据库的操作和查询。
更多关于数据库的连接、操作、查询、多数据库使用等,请参考[DataModel数据模型 - PhalApi 2.x 开发文档](http://docs.phalapi.net/#/v2.0/database-datamodel)。
## 如何新增API接口命名空间
默认情况推荐将接口统一放置在App命名空间即src/app目录下。如果项目有需要可以新增自己的接口命名空间。
首先,参考开源版文档[如何增加一个顶级命名空间?](http://docs.phalapi.net/#/v2.0/autoload?id=%e5%a6%82%e4%bd%95%e5%a2%9e%e5%8a%a0%e4%b8%80%e4%b8%aa%e9%a1%b6%e7%ba%a7%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%ef%bc%9f),增加一个新的顶级命名空间。
然后,修改```./config/app.php```配置文件里的open_api_namespaces配置追加你的命名空间。
```php
// 开放接口的命名空间,配置后可提供接口权限分配,可配置多个
'open_api_namespaces' => array('App', '新的顶级命名空间'),
```
例如加了Task命名空间后
```php
// 开放接口的命名空间,配置后可提供接口权限分配,可配置多个
'open_api_namespaces' => array('App', 'Task'),
```
在管理后台可以自动管理该命名空间下的接口权限。
接口权限分配:
![](http://cdn7.okayapi.com/yesyesapi_20200416114254_3c9a241aa03b33b0b66911583c8bd568.jpg)
接口服务列表:
![](http://cdn7.okayapi.com/yesyesapi_20200416114450_1d98c314d1c0eef0f34aad607a4ce076.jpg)
在开放平台,开发者也可自动看到新增命名空间下的接口。
![](http://cdn7.okayapi.com/yesyesapi_20200416114634_7ac7f4d70c1c4e138eac7206c2134e46.png)
## 如何隐藏接口?
和开源版一样,在接口类或方法中添加```@ignore```注释。
如:
```php
<?php
namespace App\Api;
use App\Common\Api;
/**
* Hello World示例
* @ignore
*/
class HelloWorld extends Api {
/**
* 接口示例
* @desc 一个开放接口示例可直接访问不需要任何验证因为配置了service_whitelist白名单。熟悉后可删除此示例接口。
* @ignore
* @return string content 一句话
*/
public function say() {
return array('content' => 'Hello PhalApi Pro!');
}
}
```
## 如何开启接口参数加密传输?
为了保护客户端传递的参数不被外界非法获取除了使用HTTPS协议外也可以通过代码方式来增加。
在PhalApi专业版你可以
** 客户端RSA公钥加密传输API接口参数 + 服务端RSA私钥解密API接口参数。**
### 重要配置
首先是RSA私钥和公钥的文件分别是
+ rsa私钥文件./config/phalapi_pro_rsa.pri
+ rsa公钥文件./config/phalapi_pro_rsa.pub
在项目启动或开始时你可以更换以上RSA配置文件项目开始使用后不建议再更换。
其次,还可以开启./config/app.php配置文件中的encrypt_data公共参数方便客户端查看可以传递此参数以及其格式要求说明。
```php
/**
* 应用接口层的统一参数
*/
'apiCommonRules' => array(
'accessToken' => array('name' => 'access_token', 'default' => '', 'desc' => '访问令牌仅当开启签名验证时需要传递生成令牌可使用App.Auth.ApplyToken接口'),
/** ----- 如果你需要使用第二套加密算法,请开启以下参数规则 ----- **/
// 'app_key' => array('name' => 'app_key', 'default' => '', 'desc' => 'app_key用于区分客户端应用首次接入需要创建应用并等待管理员审核通过'),
// 'sign' => array('name' => 'sign', 'desc' => '动态签名,签名算法是:<br/><ul><li>1、全部参数排除sign按key进行字典排序</li><li>2、全部参数值把原始值按字符串进行拼接并在最后加上app_secret密钥</li><li>3、对第2步结果拼接密钥后进行MD5加密</li><li>4、对第3步结果转成大写得到sign签名32位</li></ul>'),
// 'uid' => array('name' => 'uid', 'type' => 'int', 'default' => 0, 'desc' => ''),
// 'accessToken' => array('name' => 'access_token', 'default' => '', 'desc' => '访问令牌,保留使用但不需要在文档上展示', 'is_doc_hide' => true),
'encryptData' => array('name' => 'encrypt_data', 'desc' => '客户端加密的接口格式是RSA公钥加密(base64编码(JSON原始数据))。开启后,同时支持原来普通的参数传递方式。'),
),
```
### 客户端RSA公钥加密传输API接口参数
将rsa公钥文件./config/phalapi_pro_rsa.pub提供给受信任的客户端开发人员其中待加密的encrypt_data参数格式是
encrypt_data = RSA公钥加密(base64编码(JSON原始数据))
也就是:
+ 第1步、把全部的原始参数通过JSON格式封装
+ 第2步、对第1步结果进行base64编码
+ 第3步、使用RSA公钥进行加密
+ 第4步、得到encrypt_data
以下是PHP作为客户端编写的代码示例
```php
// 公钥加密-由客户端完成
$public_key = openssl_pkey_get_public(file_get_contents('./phalapi_pro_rsa.pub'));
openssl_public_encrypt('{"name":"phalapi pro"}', $crypted, $public_key);
$_REQUEST['encrypt_data'] = base64_encode($crypted);
// K07LIy/V+cfZqfHgZpIPnmdkwlkFbTkyRXVXx2JfQrF3YFAIsFcHnC9TjGTezzyup2f0V24nYH71Uf3oXVIqz/X9wgPXW0AGAbJw4kDOIq9Jao5L0mG7t5FV/2DLzJ14qO6fvANv6e/Hy2pFBcKvHnQ8uRJ/wyAV+RpUAa21wCY6zzuo9OhS89NPZg4B4CUORR8SIuIqWTUlXHB0woFIfRiO/AKCGltc9oDkyzJFYVvgI0LwijkQUV9RoruCEx6EvmZY7OVLB5+AXwfnfFKKtCw3jucqHyclzXwCQoif8FXN1NzCNpYvwj7DbzqU/WzRgxnPgXQSyjbCDlw19BrWoQ==
```
以上,原始的参数是:```{"name":"phalapi pro"}```,最后加密后的结果如上。
> 温馨提示客户端可以把需要加密的参数放到encrypt_data同时服务端接口也会继续支持原来原始参数的传递。两者重复时以加密的参数为准。
### 服务端RSA私钥解密API接口参数
此部分由后端API接口自动完成。不影响原有的接口参数传递方式和接口参数规则配置。
## composer的使用
PhalApi专业版和PhalApi 2.x开源一样都是使用了composer如果对PHP composer不熟悉可以查看[Composer 中文网 / Packagist 中国全量镜像](https://www.phpcomposer.com/)简单来说composer是 PHP 用来管理依赖dependency关系的工具。
由于国外镜像通常会很慢,本地使用时可以切换到中国镜像。执行以下命令:
```
$ composer config -g repo.packagist composer https://packagist.phpcomposer.com
```
## 扩展阅读
更多内容请参考[PhalApi 2.x 开发文档](http://docs.phalapi.net/#/)。