Kaynağa Gözat

api模块创建,配置更新与测试中,路由规则测试中

shishao-home 6 yıl önce
ebeveyn
işleme
57f0ed629a

+ 109 - 0
app/api/components/Jwt.php

@@ -0,0 +1,109 @@
+<?php
+namespace api\components;
+
+/**
+ * Created by PhpStorm.
+ * User: shizhongqi
+ * Date: 2019/11/19
+ * Time: 21:37
+ */
+use Lcobucci\JWT\Builder;
+use Lcobucci\JWT\Claim\Factory as ClaimFactory;
+use Lcobucci\JWT\Parser;
+use Lcobucci\JWT\Parsing\Decoder;
+use Lcobucci\JWT\Parsing\Encoder;
+use Lcobucci\JWT\Signer\Key;
+use Lcobucci\JWT\Token;
+use Lcobucci\JWT\ValidationData;
+use Yii;
+//use yii\base\Component;
+use yii\base\InvalidParamException;
+
+class Jwt
+{
+    /**
+     * @var array 支持的加密算法
+     */
+    public $supportedAlgs = [
+        'HS256' => 'Lcobucci\JWT\Signer\Hmac\Sha256',
+        'HS384' => 'Lcobucci\JWT\Signer\Hmac\Sha384',
+        'HS512' => 'Lcobucci\JWT\Signer\Hmac\Sha512',
+    ];
+
+    /**
+     * 创建JWT生成器
+     * @param Encoder|null $encoder
+     * @param ClaimFactory|null $claimFactory
+     * @return Builder
+     */
+    public function getBuilder(Encoder $encoder = null, ClaimFactory $claimFactory = null)
+    {
+        return new Builder($encoder, $claimFactory);
+    }
+
+    /**
+     * 创建JWT解析器
+     * @param Decoder|null $decoder
+     * @param ClaimFactory|null $claimFactory
+     * @return Parser
+     */
+    public function getParser(Decoder $decoder = null, ClaimFactory $claimFactory = null)
+    {
+        return new Parser($decoder, $claimFactory);
+    }
+
+    /**
+     * 验证JWT,并返回一个令牌类
+     * @param $token
+     * @param bool $validate
+     * @param bool $verify
+     * @return Token|null
+     */
+    public function validateJwt($token, $validate = true, $verify = true)
+    {
+        try {
+            $token = $this->getParser()->parse((string)$token);
+        } catch (\RuntimeException $e) {
+            // Yii::warning("Invalid JWT provided: " . $e->getMessage(), 'jwt');
+            return null;
+        } catch (\InvalidArgumentException $e) {
+            // Yii::warning("Invalid JWT provided: " . $e->getMessage(), 'jwt');
+            return null;
+        }
+        if ($validate && !$this->validateToken($token)) {
+            return null;
+        }
+        if ($verify && !$this->verifyToken($token)) {
+            return null;
+        }
+        return $token;
+    }
+
+    /**
+     * 数据验证
+     * @param Token $token
+     * @param null $currentTime
+     * @return bool
+     */
+    public function validateToken(Token $token, $currentTime = null)
+    {
+        $data = new ValidationData($currentTime);
+        // @todo Add claims for validation
+        return $token->validate($data);
+    }
+
+    /**
+     * Validate token
+     * @param Token $token
+     * @return bool
+     */
+    public function verifyToken(Token $token)
+    {
+        $alg = $token->getHeader('alg');
+        if (empty($this->supportedAlgs[$alg])) {
+            throw new InvalidParamException('Algorithm not supported');
+        }
+        $signer = Yii::createObject($this->supportedAlgs[$alg]);
+        return $token->verify($signer, new Key('jwt_secret'));
+    }
+}

+ 72 - 0
app/api/components/ResBeforeSendBehavior.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: admin
+ * Date: 2019/11/20
+ * Time: 0:31
+ */
+
+namespace api\components;
+
+
+use Yii;
+use yii\web\Response;
+use yii\base\Behavior;
+
+class ResBeforeSendBehavior extends Behavior{
+
+    public $defaultCode = 500;
+
+    public $defaultMsg = 'error';
+
+    // 重载events() 使得在事件触发时,调用行为中的一些方法
+    public function events() {
+        // 在 EVENT_BEFORE_SEND 事件触发时,调用成员函数 beforeSend
+        return [
+            Response::EVENT_BEFORE_SEND => 'beforeSend',
+        ];
+    }
+
+    // 注意 beforeSend 是行为的成员函数,而不是绑定的类的成员函数。
+    // 还要注意,这个函数的签名,要满足事件 handler 的要求。
+    public function beforeSend($event)
+    {
+        try {
+            $response = $event->sender;
+            if($response->data === null){
+                $response->data = [
+                    'code'  => $this->defaultCode,
+                    'msg'   => $this->defaultMsg,
+                ];
+            } elseif(!$response->isSuccessful) {
+                $exception = Yii::$app->getErrorHandler()->exception;
+                if(is_object($exception) && !$exception instanceof yii\web\HttpException){
+                    throw $exception;
+                } else {
+                    $rData = $response->data;
+                    $response->data = [
+                        'code'  => empty($rData['status']) ? $this->defaultCode : $rData['status'],
+                        'msg'   => empty($rData['message']) ? $this->defaultMsg : $rData['message'],
+                    ];
+                }
+            } else {
+                /**
+                 * $response->isSuccessful 表示是否会抛出异常
+                 * 值为 true, 代表返回数据正常,没有抛出异常
+                 */
+                $rData = $response->data;
+                $response->data = [
+                    'code' => isset($rData['error_code']) ? $rData['error_code'] : 0,
+                    'msg' => isset($rData['res_msg']) ? $rData['res_msg'] : $rData,
+                ];
+                $response->statusCode = 200;
+            }
+        } catch (\Exception $e) {
+            $response->data = [
+                'code'  => $this->defaultCode,
+                'msg'   => $this->defaultMsg,
+            ];
+        }
+        return true;
+    }
+}

+ 1 - 0
app/api/config/bootstrap.php

@@ -0,0 +1 @@
+<?php

+ 30 - 0
app/api/config/main-local.php

@@ -0,0 +1,30 @@
+<?php
+
+$config = [
+    'components' => [
+        'request' => [
+            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+            'cookieValidationKey' => '3i18DOM7ZDqqQfr2S0hj0c60wFxxTb56',
+            'parsers' => [
+                'application/json' => 'yii\web\JsonParser',
+
+            ],
+        ],
+    ],
+];
+
+if (!YII_ENV_TEST) {
+    // configuration adjustments for 'dev' environment
+    $config['bootstrap'][] = 'debug';
+    $config['modules']['debug'] = [
+        'class' => 'yii\debug\Module',
+	    'allowedIPs' => ['*'],
+    ];
+    $config['bootstrap'][] = 'zhhHuahuibaoGii';
+    $config['modules']['zhhHuahuibaoGii'] = [
+        'class' => 'yii\gii\Module',
+        'allowedIPs' => ['*'],
+    ];
+}
+
+return $config;

+ 124 - 0
app/api/config/main.php

@@ -0,0 +1,124 @@
+<?php
+$params = array_merge (
+	require(__DIR__ . '/../../../common/config/params.php'),
+	require(__DIR__ . '/../../../common/config/params-local.php'),
+	require(__DIR__ . '/params.php'),
+	require(__DIR__ . '/params-local.php')
+);
+
+return [
+    'id' => 'app-api',
+    'basePath' => dirname(__DIR__),
+    'bootstrap' => [
+        'log',
+        //全局内容协商
+        [
+            //ContentNegotiator 类可以分析request的header然后指派所需的响应格式给客户端,不需要我们人工指定
+            'class'     => 'yii\filters\ContentNegotiator',
+            'formats' => [
+                'application/json' => yii\web\Response::FORMAT_JSON,
+                'application/xml' => yii\web\Response::FORMAT_XML,
+                //api 端目前只需要json 和 xml
+                //还可以增加 yii\web\Response 类内置的响应格式,或者自己增加响应格式
+            ],
+        ]
+    ],
+    'defaultRoute' => 'main/index',//默认控制器
+    'controllerNamespace' => 'api\controllers',
+    //新增中 -- shizhongqi
+    'modules' => [
+        /*'v1' => [
+            'class' => '\modules\v1\Module',
+        ],*/
+    ],
+
+    //
+    'components' => [
+        'jwt' => [
+            'class' => 'api\components\Jwt',
+        ],
+	    'user' => [
+		    'identityClass' => 'common\models\xhAdmin',
+		    'enableAutoLogin' => true,
+		    'identityCookie' => [
+		    	'name' => 'backendUser', // unique for backend
+		    ],
+		    'loginUrl' => ['main/login'],
+	    ],
+        'db' => [
+	        'class' => 'yii\db\Connection',
+	        'dsn' => 'mysql:host=127.0.0.1;dbname=huahuibao',
+	        'username' => 'root',
+	        'password' => '353167',
+	        'charset' => 'utf8',
+        ],
+        'log' => [
+            'traceLevel' => YII_DEBUG ? 3 : 0,
+            'targets' => [
+                [
+                    'class' => 'yii\log\FileTarget',
+                    'levels' => ['error', 'warning'],
+                ],
+            ],
+        ],
+
+        //新增,不理解有什么用处,后期了解下 -- shizhonqi
+        'response' => [
+            'class'     => 'yii\web\Response',
+            //设置 api 返回格式,错误码不在 header 里实现,而是放到 body里
+            'as resBeforeSend' => [
+                'class'         => 'api\components\ResBeforeSendBehavior',
+                'defaultCode'   => 500,
+                'defaultMsg'    => 'error',
+            ],
+            //ps:components 中绑定事件,可以用两种方法
+            //'on eventName' => $eventHandler,
+            //'as behaviorName' => $behaviorConfig,
+            //参考 http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html#configuration-format
+        ],
+        /*'errorHandler' => [
+            'errorAction' => 'site/error',
+        ],*/
+
+        //变动 -- shizhonqi
+        //TODO 路由规则验证中
+        'urlManager' => [
+            'enablePrettyUrl' => true,
+            // 注意:如果不需要严格解析路由请直接删除或注释此行代码
+//          'enableStrictParsing' => true,
+            // 是否在URL中显示入口脚本。是对美化功能的进一步补充。
+            'showScriptName' => false,
+
+            //路由不正确也能正常运行 -- ???
+            'rules' => [
+                '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
+                [
+                    'class' => 'yii\rest\UrlRule',
+                    'controller' => 'user',
+                    'pluralize' => false,    //设置为false 就可以去掉复数形式了*/
+                    'extraPatterns'=>[
+                        'GET test'=>'test'
+                    ],
+                ],
+
+                //"GET user/create" => "user/create",
+
+                //当然,如果自带的路由无法满足需求,可以自己增加规则
+                'GET <module:(v)\d+>/<controller:\w+>/search' => '<module>/<controller>/search',
+                [
+                    'class'         => 'yii\rest\UrlRule',
+                    'controller'    => ['v1/user'],
+                    // 由于 resetful 风格规定 URL 保持格式一致并且始终使用复数形式
+                    // 所以如果你的 controller 是单数的名称比如 UserController
+                    // 设置 pluralize 为 true (默认为 true)的话,url 地址必须是 users 才可访问
+                    // 如果 pluralize 设置为 false, url 地址必须是 user 也可访问
+                    // 如果你的 controller 本身是复数名称 UsersController ,此参数没用,url 地址必须是 users
+                    'pluralize' => false,
+                ],
+            ],
+        ],
+    ],
+    'params' => $params,
+]
+
+;

+ 3 - 0
app/api/config/params-local.php

@@ -0,0 +1,3 @@
+<?php
+return [
+];

+ 4 - 0
app/api/config/params.php

@@ -0,0 +1,4 @@
+<?php
+return [
+    'adminEmail' => 'admin@example.com',
+];

+ 17 - 0
app/api/controllers/MainController.php

@@ -0,0 +1,17 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: admin
+ * Date: 2019/11/19
+ * Time: 22:43
+ */
+
+namespace api\controllers;
+
+use yii\rest\ActiveController;
+
+
+class MainController extends ActiveController
+{
+
+}

+ 56 - 0
app/api/controllers/UserController.php

@@ -0,0 +1,56 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: shizhongqi
+ * Date: 2019/11/19
+ * Time: 22:43
+ */
+
+namespace api\controllers;
+
+use Yii;
+use yii\rest\ActiveController;
+use \Lcobucci\JWT\Signer\Hmac\Sha256;
+
+class UserController extends ActiveController
+{
+    public $modelClass = 'common\models\xhUser';
+
+    public function actions()
+    {
+        $action= parent::actions(); // TODO: Change the autogenerated stub
+        unset($action['index']);
+        unset($action['create']);
+        unset($action['update']);
+        unset($action['delete']);
+    }
+
+    public function actionIndex()
+    {
+        return ['status'=>200, 'msg'=>'success'];
+    }
+
+    public function actionTest()
+    {
+        $builder = Yii::$app->jwt->getBuilder();
+
+        $signer  = new Sha256();
+
+        $secret = "suspn@)!*";
+
+        //设置header和payload,以下的字段都可以自定义
+        $builder->setIssuer("suspn.com") //发布者
+        ->setAudience("suspn.com") //接收者
+        ->setId("abc", true) //对当前token设置的标识
+        ->setIssuedAt(time()) //token创建时间
+        ->setExpiration(time() + 60) //过期时间
+        ->setNotBefore(time() + 5) //当前时间在这个时间前,token不能使用
+        ->set('uid', 30061); //自定义数据
+
+        //设置签名
+        $builder->sign($signer, $secret);
+        //获取加密后的token,转为字符串
+        $token = (string)$builder->getToken();
+        var_dump($token);
+    }
+}

BIN
app/api/web/favicon.ico


+ 19 - 0
app/api/web/index-test.php

@@ -0,0 +1,19 @@
+<?php
+
+// NOTE: Make sure this file is not accessible when deployed to production
+if (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
+    die('You are not allowed to access this file.');
+}
+
+defined('YII_DEBUG') or define('YII_DEBUG', true);
+defined('YII_ENV') or define('YII_ENV', 'test');
+
+require(__DIR__ . '/../../vendor/autoload.php');
+require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
+require(__DIR__ . '/../../common/config/bootstrap.php');
+require(__DIR__ . '/../config/bootstrap.php');
+
+
+$config = require(__DIR__ . '/../../tests/codeception/config/api/acceptance.php');
+
+(new yii\web\Application($config))->run();

+ 19 - 0
app/api/web/index.php

@@ -0,0 +1,19 @@
+<?php
+error_reporting(E_ALL);
+defined('YII_DEBUG') or define('YII_DEBUG', true);
+defined('YII_ENV') or define('YII_ENV', 'dev');
+
+require(__DIR__ . '/../../../vendor/autoload.php');
+require(__DIR__ . '/../../../vendor/yiisoft/yii2/Yii.php');
+require(__DIR__ . '/../../../common/config/bootstrap.php');
+require(__DIR__ . '/../config/bootstrap.php');
+
+$config = yii\helpers\ArrayHelper::merge(
+    require(__DIR__ . '/../../../common/config/main.php'),
+    require(__DIR__ . '/../../../common/config/main-local.php'),
+    require(__DIR__ . '/../config/main.php'),
+    require(__DIR__ . '/../config/main-local.php')
+);
+
+$application = new yii\web\Application($config);
+$application->run();

+ 2 - 0
app/api/web/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /