ThinkPHP 6.0 多应用模式下API接口开发与JWT认证实战教程 | PHP框架进阶

2026-01-25 0 853
免费资源下载

作者:技术架构师 | 发布日期:2023年10月

一、项目架构设计思路

在传统的ThinkPHP单应用模式下,前后端代码往往耦合在一起。现代开发更倾向于前后端分离架构,多应用模式为此提供了完美解决方案。本教程将构建一个包含admin管理端api接口端的双应用项目。

1.1 环境要求与初始化

# 创建ThinkPHP 6.0项目
composer create-project topthink/think tp6-api-project

# 进入项目目录安装多应用扩展
cd tp6-api-project
composer require topthink/think-multi-app

# 验证安装
php think version

二、多应用配置与目录结构

2.1 应用创建与配置

# 创建api和admin应用
php think build api
php think build admin

# 目录结构展示
app/
├── api/              # API接口应用
│   ├── controller/   # 控制器目录
│   ├── middleware/   # 中间件目录
│   └── service/      # 业务逻辑层
├── admin/            # 后台管理应用
│   ├── controller/
│   └── view/
└── common/           # 公共模块
    ├── lib/          # 公共库
    └── trait/        # 特征类

2.2 路由独立配置

每个应用拥有独立的路由配置文件:

# app/api/route/app.php
use thinkfacadeRoute;

Route::group('api', function () {
    Route::post('login', 'auth/login');
    Route::get('user/profile', 'user/profile');
})->middleware(['ApiAuth']);

三、JWT认证系统实现

3.1 JWT工具类封装

// app/common/lib/JwtAuth.php
namespace appcommonlib;

use FirebaseJWTJWT;
use FirebaseJWTKey;

class JwtAuth
{
    private static $key = 'your-secret-key-2023';
    private static $alg = 'HS256';
    
    /**
     * 生成Token
     * @param array $data 用户数据
     * @param int $expire 过期时间(秒)
     * @return string
     */
    public static function createToken(array $data, int $expire = 7200): string
    {
        $payload = [
            'iss' => 'tp6-api-server',  // 签发者
            'iat' => time(),            // 签发时间
            'exp' => time() + $expire,  // 过期时间
            'data' => $data            // 自定义数据
        ];
        
        return JWT::encode($payload, self::$key, self::$alg);
    }
    
    /**
     * 验证Token
     * @param string $token
     * @return array|bool
     */
    public static function verifyToken(string $token)
    {
        try {
            $decoded = JWT::decode($token, new Key(self::$key, self::$alg));
            return (array)$decoded->data;
        } catch (Exception $e) {
            return false;
        }
    }
}

3.2 认证中间件实现

// app/api/middleware/ApiAuth.php
namespace appapimiddleware;

use appcommonlibJwtAuth;

class ApiAuth
{
    public function handle($request, Closure $next)
    {
        $token = $request->header('Authorization');
        
        if (!$token) {
            return json(['code' => 401, 'msg' => 'Token缺失']);
        }
        
        // 移除Bearer前缀
        if (str_starts_with($token, 'Bearer ')) {
            $token = substr($token, 7);
        }
        
        $userData = JwtAuth::verifyToken($token);
        
        if (!$userData) {
            return json(['code' => 401, 'msg' => 'Token无效或已过期']);
        }
        
        // 将用户数据存入请求对象
        $request->user = $userData;
        
        return $next($request);
    }
}

四、统一响应格式封装

4.1 响应特征类设计

// app/common/trait/ApiResponse.php
namespace appcommontrait;

trait ApiResponse
{
    /**
     * 成功响应
     * @param mixed $data 响应数据
     * @param string $msg 提示信息
     * @param int $code 状态码
     * @return thinkResponse
     */
    protected function success($data = null, string $msg = '操作成功', int $code = 200)
    {
        return $this->jsonResponse($code, $msg, $data);
    }
    
    /**
     * 错误响应
     * @param string $msg 错误信息
     * @param int $code 状态码
     * @param mixed $data 附加数据
     * @return thinkResponse
     */
    protected function error(string $msg = '操作失败', int $code = 400, $data = null)
    {
        return $this->jsonResponse($code, $msg, $data);
    }
    
    /**
     * JSON响应统一封装
     */
    private function jsonResponse(int $code, string $msg, $data)
    {
        $response = [
            'code' => $code,
            'msg'  => $msg,
            'data' => $data,
            'time' => time(),
            'request_id' => uniqid('api_', true)
        ];
        
        return json($response)->header([
            'Content-Type' => 'application/json; charset=utf-8'
        ]);
    }
}

4.2 控制器应用示例

// app/api/controller/AuthController.php
namespace appapicontroller;

use appBaseController;
use appcommontraitApiResponse;
use appcommonlibJwtAuth;

class AuthController extends BaseController
{
    use ApiResponse;
    
    /**
     * 用户登录接口
     * @return thinkResponse
     */
    public function login()
    {
        $username = $this->request->param('username');
        $password = $this->request->param('password');
        
        // 验证逻辑(示例)
        if ($username !== 'admin' || $password !== '123456') {
            return $this->error('用户名或密码错误', 401);
        }
        
        // 用户数据
        $userData = [
            'user_id' => 1,
            'username' => $username,
            'role' => 'admin'
        ];
        
        // 生成Token
        $token = JwtAuth::createToken($userData);
        
        return $this->success([
            'token' => $token,
            'user_info' => $userData,
            'expires_in' => 7200
        ], '登录成功');
    }
    
    /**
     * 获取用户资料
     * @return thinkResponse
     */
    public function profile()
    {
        // 通过中间件注入的用户数据
        $user = $this->request->user;
        
        // 模拟从数据库获取详细信息
        $profile = [
            'user_id' => $user['user_id'],
            'username' => $user['username'],
            'email' => 'user@example.com',
            'avatar' => 'https://api.example.com/avatar/default.png',
            'created_at' => '2023-01-01'
        ];
        
        return $this->success($profile, '获取成功');
    }
}

五、数据库设计与模型层

5.1 用户表迁移文件

// database/migrations/20231001000000_create_users_table.php
use thinkmigrationMigrator;
use thinkmigrationdbColumn;

class CreateUsersTable extends Migrator
{
    public function change()
    {
        $table = $this->table('users', [
            'engine' => 'InnoDB',
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'comment' => '用户表'
        ]);
        
        $table->addColumn('username', 'string', [
            'limit' => 50,
            'null' => false,
            'default' => '',
            'comment' => '用户名'
        ])
        ->addColumn('password_hash', 'string', [
            'limit' => 255,
            'null' => false,
            'comment' => '密码哈希'
        ])
        ->addColumn('email', 'string', [
            'limit' => 100,
            'null' => true,
            'comment' => '邮箱'
        ])
        ->addColumn('status', 'integer', [
            'limit' => 1,
            'default' => 1,
            'comment' => '状态:1正常 0禁用'
        ])
        ->addColumn('last_login_ip', 'string', [
            'limit' => 45,
            'null' => true,
            'comment' => '最后登录IP'
        ])
        ->addColumn('last_login_time', 'integer', [
            'null' => true,
            'comment' => '最后登录时间'
        ])
        ->addTimestamps()  // 创建created_at和updated_at字段
        ->addIndex(['username'], ['unique' => true])
        ->addIndex(['email'])
        ->addIndex(['status'])
        ->create();
    }
}

5.2 模型层封装

// app/common/model/UserModel.php
namespace appcommonmodel;

use thinkModel;
use thinkmodelconcernSoftDelete;

class UserModel extends Model
{
    use SoftDelete;
    
    protected $table = 'users';
    protected $pk = 'id';
    
    // 自动时间戳
    protected $autoWriteTimestamp = true;
    protected $createTime = 'created_at';
    protected $updateTime = 'updated_at';
    protected $deleteTime = 'deleted_at';
    
    // 字段类型转换
    protected $type = [
        'status' => 'integer',
        'last_login_time' => 'timestamp'
    ];
    
    // 密码加密
    public function setPasswordAttr($value)
    {
        return password_hash($value, PASSWORD_DEFAULT);
    }
    
    // 验证密码
    public function verifyPassword($inputPassword, $storedHash)
    {
        return password_verify($inputPassword, $storedHash);
    }
}

六、API接口测试与文档

6.1 Postman测试示例

登录接口测试:

  • URL: POST http://your-domain.com/api/login
  • Headers: Content-Type: application/json
  • Body: {“username”: “admin”, “password”: “123456”}

获取用户资料测试:

  • URL: GET http://your-domain.com/api/user/profile
  • Headers: Authorization: Bearer {your_token}

6.2 接口响应示例

// 成功响应
{
    "code": 200,
    "msg": "登录成功",
    "data": {
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
        "user_info": {
            "user_id": 1,
            "username": "admin",
            "role": "admin"
        },
        "expires_in": 7200
    },
    "time": 1696156800,
    "request_id": "api_650f1a2b3c4d5"
}

// 错误响应
{
    "code": 401,
    "msg": "Token无效或已过期",
    "data": null,
    "time": 1696156800,
    "request_id": "api_650f1a2b3c4d6"
}

七、性能优化与安全建议

7.1 性能优化措施

  1. 路由缓存:生产环境开启路由缓存 php think optimize:route
  2. 配置缓存:使用 php think optimize:config 加速配置加载
  3. OPCache:启用PHP OPcache扩展提升执行效率
  4. 数据库连接池:使用Swoole等扩展实现连接复用

7.2 安全加固建议

  1. Token刷新机制:实现双Token方案(access_token + refresh_token)
  2. 接口限流:使用中间件限制单位时间内的请求次数
  3. SQL防注入:使用模型查询或参数绑定,避免原生SQL
  4. XSS防护:输出时使用htmlspecialchars过滤
  5. CORS配置:严格设置跨域访问白名单

八、部署与监控

8.1 Nginx配置示例

server {
    listen 80;
    server_name api.yourdomain.com;
    root /var/www/tp6-api-project/public;
    index index.php;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location ~ .php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        
        # 增加超时时间
        fastcgi_read_timeout 300;
    }
    
    # 禁止访问敏感文件
    location ~ /.(git|env|ht) {
        deny all;
    }
    
    # 静态文件缓存
    location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

8.2 日志监控配置

// config/log.php 部分配置
return [
    'default' => 'file',
    'channels' => [
        'file' => [
            'type' => 'file',
            'path' => app()->getRuntimePath() . 'log/',
            'level' => ['error', 'sql', 'api'],
            'apart_level' => ['error', 'sql'], // 独立记录
            'max_files' => 30, // 最多保存30天
        ],
        'api' => [
            'type' => 'file',
            'path' => app()->getRuntimePath() . 'log/api/',
            'level' => ['info', 'error'],
            'format' => '[%s][%s] %s', // 自定义格式
        ]
    ]
];
ThinkPHP 6.0 多应用模式下API接口开发与JWT认证实战教程 | PHP框架进阶
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 thinkphp ThinkPHP 6.0 多应用模式下API接口开发与JWT认证实战教程 | PHP框架进阶 https://www.taomawang.com/server/thinkphp/1564.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务