diff --git a/FAQ.md b/FAQ.md index 17dcdff..e56bca7 100644 --- a/FAQ.md +++ b/FAQ.md @@ -30,29 +30,32 @@ APP_DEBUG = true ## 2. 路由和访问 ### Q: 如何访问 API 接口? -A: URL 格式为 `http://域名/应用名/控制器/方法` -- 示例:`http://localhost:8000/api/index/index` -- 或使用路由:`http://localhost:8000/api/index`(需配置路由) +A: 当前项目使用固定路由入口,认证接口统一走 `http://域名/api/v1/auth/*` +- 登录:`POST http://localhost:8000/api/v1/auth/login` +- 注册:`POST http://localhost:8000/api/v1/auth/register` +- 当前用户:`GET http://localhost:8000/api/v1/auth/me` ### Q: 如何添加新的路由? -A: 在 `route/api.php` 文件中添加路由规则: +A: 在 `app/api/route/app.php` 文件中添加路由规则: ```php -Route::get('user/profile', 'api.User/profile'); -Route::post('user/update', 'api.User/update'); +use app\api\controller\v1\Auth; + +Route::post('v1/auth/login', [Auth::class, 'login']); +Route::post('v1/auth/register', [Auth::class, 'register']); ``` ### Q: 如何设置路由参数? A: 使用 `:参数名` 格式: ```php -Route::get('user/:id', 'api.User/detail'); +Route::get('v1/example/:id', 'v1.Example/detail'); ``` ## 3. 控制器开发 ### Q: 如何创建新的控制器? A: -1. 手动创建:在 `app/api/controller/` 目录下创建 PHP 文件 -2. 使用命令:`php think make:controller api@Demo` +1. 手动创建:在 `app/api/controller/v1/` 目录下创建 PHP 文件 +2. 使用命令:`php think make:controller api@v1/Auth` ### Q: 如何返回 JSON 数据? A: 使用基础控制器提供的方法: @@ -97,7 +100,10 @@ $this->validate($data, [ 2. 使用验证器: ```php -$this->validate($data, 'app\api\validate\User.register'); +$this->validate($data, [ + 'username' => 'require|alphaNum', + 'password' => 'require|length:6,20', +]); ``` ### Q: 如何自定义验证错误信息? @@ -137,8 +143,8 @@ A: 1. 全局中间件:在 `app/api/middleware.php` 中注册 2. 路由中间件:在路由定义中使用 ```php -Route::group('api', function () { - Route::get('user/info', 'api.User/info'); +Route::group('v1/auth', function () { + Route::get('me', [\app\api\controller\v1\Auth::class, 'me']); })->middleware(\app\api\middleware\Auth::class); ``` @@ -148,27 +154,28 @@ Route::group('api', function () { A: ```php // 查询单条 -$user = \app\api\model\User::find(1); +$member = \app\api\model\Member::findByUserid(1); // 查询多条 -$users = \app\api\model\User::where('status', 1)->select(); +$members = \app\api\model\Member::where('disabled', 0)->select(); // 新增 -$user = new \app\api\model\User; -$user->username = 'test'; -$user->save(); +$member = new \app\api\model\Member; +$member->username = 'test'; +$member->password = password_hash('123456', PASSWORD_DEFAULT); +$member->save(); // 或 -\app\api\model\User::create([ +\app\api\model\Member::create([ 'username' => 'test', - 'password' => '123456', + 'password' => password_hash('123456', PASSWORD_DEFAULT), ]); // 更新 -\app\api\model\User::update(['id' => 1, 'status' => 0]); +\app\api\model\Member::update(['userid' => 1, 'disabled' => 1]); // 删除 -\app\api\model\User::destroy(1); +\app\api\model\Member::destroy(1); ``` ### Q: 如何使用事务? diff --git a/README_API.md b/README_API.md index 06c5f2d..84fb1d2 100644 --- a/README_API.md +++ b/README_API.md @@ -12,24 +12,26 @@ ``` tp/ -├── app/ # 应用目录 -│ ├── api/ # API 应用 -│ │ ├── controller/ # 控制器 -│ │ │ ├── BaseController.php # 基础控制器 -│ │ │ ├── Index.php # 首页控制器 -│ │ │ └── User.php # 用户控制器 -│ │ ├── model/ # 模型 -│ │ ├── validate/ # 验证器 -│ │ ├── middleware/ # 中间件 -│ │ │ ├── Auth.php # 认证中间件 -│ │ │ └── CrossDomain.php # 跨域中间件 -│ │ ├── common/ # 公共类 -│ │ │ └── Response.php # 统一响应类 -│ │ └── AppService.php # 应用服务 -│ └── BaseController.php # 默认基础控制器 +├── app/ +│ └── api/ +│ ├── controller/ +│ │ ├── BaseController.php +│ │ └── v1/ +│ │ └── Auth.php +│ ├── model/ +│ │ └── Member.php +│ ├── service/ +│ │ └── AuthService.php +│ ├── middleware/ +│ │ ├── Auth.php +│ │ └── CrossDomain.php +│ ├── common/ +│ │ ├── Jwt.php +│ │ └── Response.php +│ ├── middleware.php +│ └── route/ +│ └── app.php ├── config/ # 配置文件 -├── route/ # 路由 -│ └── api.php # API 路由配置 ├── public/ # 公共资源 ├── runtime/ # 运行时目录 ├── vendor/ # Composer 依赖 @@ -112,43 +114,10 @@ php think run ## API 接口文档 -### 公共接口(无需认证) +### 公开接口 -#### 1. 首页信息 -- **URL**: `/api/index` -- **Method**: GET -- **响应示例**: -```json -{ - "code": 200, - "msg": "success", - "data": { - "name": "ThinkPHP API", - "version": "8.1.3", - "message": "Welcome to ThinkPHP API Application" - }, - "time": 1640000000 -} -``` - -#### 2. 健康检查 -- **URL**: `/api/health` -- **Method**: GET -- **响应示例**: -```json -{ - "code": 200, - "msg": "success", - "data": { - "status": "ok", - "timestamp": "2024-01-01 12:00:00" - }, - "time": 1640000000 -} -``` - -#### 3. 用户登录 -- **URL**: `/api/user/login` +#### 1. 用户登录 +- **URL**: `/api/v1/auth/login` - **Method**: POST - **参数**: - `username`: 用户名(必填) @@ -159,15 +128,23 @@ php think run "code": 200, "msg": "登录成功", "data": { - "token": "example_token_xxx", - "username": "demo" + "token": "jwt_access_token", + "refresh_token": "jwt_refresh_token", + "expires_in": 604800, + "user": { + "userid": 1001, + "username": "demo", + "v_type": 0, + "endtime": 0, + "formtypeid": 0 + } }, "time": 1640000000 } ``` -#### 4. 用户注册 -- **URL**: `/api/user/register` +#### 2. 用户注册 +- **URL**: `/api/v1/auth/register` - **Method**: POST - **参数**: - `username`: 用户名(3-20位) @@ -179,16 +156,31 @@ php think run "code": 200, "msg": "注册成功", "data": { - "user_id": 1001 + "token": "jwt_access_token", + "refresh_token": "jwt_refresh_token", + "expires_in": 604800, + "user": { + "userid": 1001, + "username": "demo", + "v_type": 0, + "endtime": 0, + "formtypeid": 0 + } }, "time": 1640000000 } ``` +#### 3. 刷新 Token +- **URL**: `/api/v1/auth/refresh` +- **Method**: POST +- **参数**: + - `refresh_token`: 刷新令牌 + ### 认证接口(需要 token) -#### 5. 获取用户信息 -- **URL**: `/api/user/info` +#### 4. 获取用户信息 +- **URL**: `/api/v1/auth/me` - **Method**: GET - **Headers**: `token: your_token` - **响应示例**: @@ -197,22 +189,41 @@ php think run "code": 200, "msg": "success", "data": { - "id": 1, + "userid": 1, "username": "demo_user", - "nickname": "演示用户", - "avatar": "", - "email": "demo@example.com", - "created_at": "2024-01-01 12:00:00" + "v_type": 1, + "endtime": 1777777777, + "formtypeid": 0, + "disabled": 0, + "product": { + "v_type": 1, + "video_num": 100, + "account_num": 5 + } }, "time": 1640000000 } ``` +#### 5. 退出登录 +- **URL**: `/api/v1/auth/logout` +- **Method**: POST +- **Headers**: `token: your_token` + +#### 6. 修改密码 +- **URL**: `/api/v1/auth/password` +- **Method**: POST +- **Headers**: `token: your_token` +- **参数**: + - `old_password`: 原密码 + - `new_password`: 新密码 + - `confirm_password`: 确认新密码 + ## 功能特性 ### 1. 多应用模式 - 采用 ThinkPHP 多应用扩展 -- API 接口独立目录 +- API 接口集中在 `app/api` - 便于扩展其他应用模块 ### 2. 统一响应格式 @@ -238,9 +249,6 @@ $this->validate($data, [ 'username' => 'require|length:3,20', 'password' => 'require|length:6,20', ]); - -// 或使用验证器 -$this->validate($data, 'app\api\validate\User.login'); ``` ### 5. 模型自动时间戳 @@ -287,13 +295,10 @@ php think run php think clear # 生成控制器 -php think make:controller api@Demo +php think make:controller api@v1/Auth # 生成模型 -php think make:model api@Demo - -# 生成验证器 -php think make:validate api@Demo +php think make:model api@Member ``` ## 扩展安装 diff --git a/app/AppService.php b/app/AppService.php deleted file mode 100644 index 96556e8..0000000 --- a/app/AppService.php +++ /dev/null @@ -1,22 +0,0 @@ -app = $app; - $this->request = $this->app->request; - - // 控制器初始化 - $this->initialize(); - } - - // 初始化 - protected function initialize() - {} - - /** - * 验证数据 - * @access protected - * @param array $data 数据 - * @param string|array $validate 验证器名或者验证规则数组 - * @param array $message 提示信息 - * @param bool $batch 是否批量验证 - * @return array|string|true - * @throws ValidateException - */ - protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false) - { - if (is_array($validate)) { - $v = new Validate(); - $v->rule($validate); - } else { - if (strpos($validate, '.')) { - // 支持场景 - [$validate, $scene] = explode('.', $validate); - } - $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); - $v = new $class(); - if (!empty($scene)) { - $v->scene($scene); - } - } - - $v->message($message); - - // 是否批量验证 - if ($batch || $this->batchValidate) { - $v->batch(true); - } - - return $v->failException(true)->check($data); - } - -} diff --git a/app/ExceptionHandle.php b/app/ExceptionHandle.php deleted file mode 100644 index 453d126..0000000 --- a/app/ExceptionHandle.php +++ /dev/null @@ -1,58 +0,0 @@ - 'ThinkPHP API', - 'version' => app()->version(), - 'message' => 'Welcome to ThinkPHP API Application', - ]; - - return $this->success($data); - } - - /** - * 健康检查接口 - * @return \think\response\Json - */ - public function health() - { - return $this->success([ - 'status' => 'ok', - 'timestamp' => date('Y-m-d H:i:s'), - ]); - } -} diff --git a/app/api/controller/User.php b/app/api/controller/User.php deleted file mode 100644 index dbaa4c4..0000000 --- a/app/api/controller/User.php +++ /dev/null @@ -1,81 +0,0 @@ -request->post(); - - // 验证数据 - $this->validate($data, [ - 'username' => 'require', - 'password' => 'require', - ], [ - 'username.require' => '用户名不能为空', - 'password.require' => '密码不能为空', - ]); - - // TODO: 实际的登录逻辑 - return $this->success([ - 'token' => 'example_token_' . md5($data['username']), - 'username' => $data['username'], - ], '登录成功'); - } - - /** - * 获取用户信息 - * @return \think\response\Json - */ - public function info() - { - // TODO: 从 token 或 session 中获取用户信息 - $userInfo = [ - 'id' => 1, - 'username' => 'demo_user', - 'nickname' => '演示用户', - 'avatar' => '', - 'email' => 'demo@example.com', - 'created_at' => date('Y-m-d H:i:s'), - ]; - - return $this->success($userInfo); - } - - /** - * 用户注册 - * @return \think\response\Json - */ - public function register() - { - $data = $this->request->post(); - - // 验证数据 - $this->validate($data, [ - 'username' => 'require|length:3,20', - 'password' => 'require|length:6,20', - 'email' => 'require|email', - ], [ - 'username.require' => '用户名不能为空', - 'username.length' => '用户名长度3-20位', - 'password.require' => '密码不能为空', - 'password.length' => '密码长度6-20位', - 'email.require' => '邮箱不能为空', - 'email.email' => '邮箱格式不正确', - ]); - - // TODO: 实际的注册逻辑 - return $this->success([ - 'user_id' => rand(1000, 9999), - ], '注册成功'); - } -} diff --git a/app/api/controller/V1Auth.php b/app/api/controller/v1/Auth.php similarity index 85% rename from app/api/controller/V1Auth.php rename to app/api/controller/v1/Auth.php index 70ea142..4919ba1 100644 --- a/app/api/controller/V1Auth.php +++ b/app/api/controller/v1/Auth.php @@ -1,49 +1,43 @@ authService = new AuthService(); } /** * 用户登录 * POST /api/v1/auth/login - * @return \think\response\Json */ public function login() { try { $data = $this->request->post(); - // 验证参数 - validate($data, [ + validate([ 'username' => 'require', 'password' => 'require', ], [ 'username.require' => '用户名不能为空', 'password.require' => '密码不能为空', - ]); + ])->check($data); $result = $this->authService->login( $data['username'], @@ -61,15 +55,13 @@ class Auth extends BaseController /** * 用户注册 * POST /api/v1/auth/register - * @return \think\response\Json */ public function register() { try { $data = $this->request->post(); - // 验证参数 - validate($data, [ + validate([ 'username' => 'require|length:3,20|alphaNum', 'password' => 'require|length:6,20', 'email' => 'email', @@ -80,7 +72,7 @@ class Auth extends BaseController 'password.require' => '密码不能为空', 'password.length' => '密码长度6-20位', 'email.email' => '邮箱格式不正确', - ]); + ])->check($data); $result = $this->authService->register( $data['username'], @@ -100,7 +92,6 @@ class Auth extends BaseController /** * 刷新 Token * POST /api/v1/auth/refresh - * @return \think\response\Json */ public function refresh() { @@ -122,7 +113,6 @@ class Auth extends BaseController /** * 获取当前用户信息 * GET /api/v1/auth/me - * @return \think\response\Json */ public function me() { @@ -143,19 +133,15 @@ class Auth extends BaseController /** * 退出登录 * POST /api/v1/auth/logout - * @return \think\response\Json */ public function logout() { - // JWT 无状态,退出只需客户端删除 Token - // 如果需要服务端失效,可以将 Token 加入黑名单(需要 Redis 支持) return Response::success([], '退出成功'); } /** * 修改密码 * POST /api/v1/auth/password - * @return \think\response\Json */ public function password() { @@ -167,7 +153,7 @@ class Auth extends BaseController $data = $this->request->post(); - validate($data, [ + validate([ 'old_password' => 'require', 'new_password' => 'require|length:6,20|confirm:confirm_password', ], [ @@ -175,7 +161,7 @@ class Auth extends BaseController 'new_password.require' => '新密码不能为空', 'new_password.length' => '新密码长度6-20位', 'new_password.confirm' => '两次密码输入不一致', - ]); + ])->check($data); $this->authService->changePassword( $payload['userid'], diff --git a/app/api/model/User.php b/app/api/model/User.php deleted file mode 100644 index acdfb13..0000000 --- a/app/api/model/User.php +++ /dev/null @@ -1,48 +0,0 @@ - 'integer', - 'status' => 'integer', - ]; - - // 隐藏字段 - protected $hidden = ['password', 'delete_time']; - - /** - * 密码加密 - * @param string $value - * @return string - */ - public function setPasswordAttr(string $value): string - { - return password_hash($value, PASSWORD_DEFAULT); - } - - /** - * 验证密码 - * @param string $password 明文密码 - * @param string $hash 加密后的密码 - * @return bool - */ - public static function verifyPassword(string $password, string $hash): bool - { - return password_verify($password, $hash); - } -} diff --git a/app/api/route/app.php b/app/api/route/app.php index 1e9ecab..81d28ad 100644 --- a/app/api/route/app.php +++ b/app/api/route/app.php @@ -2,35 +2,20 @@ declare(strict_types=1); use think\facade\Route; -use app\api\controller\Index; -use app\api\controller\User; -use app\api\controller\V1Auth; +use app\api\controller\v1\Auth; /** * API 应用路由 */ -// ==================== v1 版本接口 ==================== +// v1 认证接口(公开) +Route::post('v1/auth/login', [Auth::class, 'login']); +Route::post('v1/auth/register', [Auth::class, 'register']); +Route::post('v1/auth/refresh', [Auth::class, 'refresh']); -// 健康检查 (公开) -Route::get('v1/health', [Index::class, 'health']); - -// 认证接口 (公开) -Route::post('v1/auth/login', [V1Auth::class, 'login']); -Route::post('v1/auth/register', [V1Auth::class, 'register']); -Route::post('v1/auth/refresh', [V1Auth::class, 'refresh']); - -// 认证接口 (需登录) +// v1 认证接口(需登录) Route::group('v1/auth', function () { - Route::get('me', [V1Auth::class, 'me']); - Route::post('logout', [V1Auth::class, 'logout']); - Route::post('password', [V1Auth::class, 'password']); + Route::get('me', [Auth::class, 'me']); + Route::post('logout', [Auth::class, 'logout']); + Route::post('password', [Auth::class, 'password']); })->middleware(\app\api\middleware\Auth::class); - -// ==================== 兼容旧版路由 ==================== - -Route::get('index', [Index::class, 'index']); -Route::get('health', [Index::class, 'health']); -Route::post('user/login', [V1Auth::class, 'login']); -Route::post('user/register', [V1Auth::class, 'register']); -Route::get('user/info', [V1Auth::class, 'me'])->middleware(\app\api\middleware\Auth::class); diff --git a/app/api/validate/User.php b/app/api/validate/User.php deleted file mode 100644 index 85dd87e..0000000 --- a/app/api/validate/User.php +++ /dev/null @@ -1,47 +0,0 @@ - 'require|length:3,20|chsDash', - 'password' => 'require|length:6,20', - 'email' => 'require|email', - 'phone' => 'mobile', - 'nickname' => 'length:2,20', - ]; - - /** - * 验证提示信息 - */ - protected $message = [ - 'username.require' => '用户名不能为空', - 'username.length' => '用户名长度3-20位', - 'username.chsDash' => '用户名只能是汉字、字母、数字和下划线_及破折号-', - 'password.require' => '密码不能为空', - 'password.length' => '密码长度6-20位', - 'email.require' => '邮箱不能为空', - 'email.email' => '邮箱格式不正确', - 'phone.mobile' => '手机号格式不正确', - 'nickname.length' => '昵称长度2-20位', - ]; - - /** - * 验证场景 - */ - protected $scene = [ - 'login' => ['username', 'password'], - 'register' => ['username', 'password', 'email'], - 'update' => ['email', 'phone', 'nickname'], - ]; -} diff --git a/app/common.php b/app/common.php deleted file mode 100644 index 57cb6d8..0000000 --- a/app/common.php +++ /dev/null @@ -1,2 +0,0 @@ -*{ padding: 0; margin: 0; }'; - } - - public function hello($name = 'ThinkPHP8') - { - return 'hello,' . $name; - } -} diff --git a/app/event.php b/app/event.php deleted file mode 100644 index e9851bb..0000000 --- a/app/event.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - ], - - 'listen' => [ - 'AppInit' => [], - 'HttpRun' => [], - 'HttpEnd' => [], - 'LogLevel' => [], - 'LogWrite' => [], - ], - - 'subscribe' => [ - ], -]; diff --git a/app/middleware.php b/app/middleware.php deleted file mode 100644 index d2c3fda..0000000 --- a/app/middleware.php +++ /dev/null @@ -1,10 +0,0 @@ - Request::class, - 'think\exception\Handle' => ExceptionHandle::class, -]; diff --git a/app/service.php b/app/service.php deleted file mode 100644 index db1ee6a..0000000 --- a/app/service.php +++ /dev/null @@ -1,9 +0,0 @@ -middleware(\app\api\middleware\Auth::class); - -// ==================== 兼容旧版路由 ==================== - -Route::get('api/index', [Index::class, 'index']); -Route::get('api/health', [Index::class, 'health']); -Route::post('api/user/login', [V1Auth::class, 'login']); -Route::post('api/user/register', [V1Auth::class, 'register']); -Route::get('api/user/info', [V1Auth::class, 'me'])->middleware(\app\api\middleware\Auth::class); diff --git a/route/app.php b/route/app.php deleted file mode 100644 index 69071f7..0000000 --- a/route/app.php +++ /dev/null @@ -1,17 +0,0 @@ - -// +---------------------------------------------------------------------- -use think\facade\Route; - -Route::get('think', function () { - return 'hello,ThinkPHP8!'; -}); - -Route::get('hello/:name', 'index/hello'); diff --git a/test_api.sh b/test_api.sh index 3328869..96ec567 100755 --- a/test_api.sh +++ b/test_api.sh @@ -26,8 +26,9 @@ echo "2. 启动开发服务器:" echo " php think run" echo "" echo "3. 访问测试接口:" -echo " - 首页: http://localhost:8000/api/index" -echo " - 健康检查: http://localhost:8000/api/health" +echo " - 登录: POST http://localhost:8000/api/v1/auth/login" +echo " - 注册: POST http://localhost:8000/api/v1/auth/register" +echo " - 刷新 Token: POST http://localhost:8000/api/v1/auth/refresh" echo "" echo "4. 查看完整文档:" echo " cat README_API.md"