Yii2 基础版实现 Token 认证 API 服务的完整框架方案

以下是一个基于 Yii2 基础版实现 Token 认证 API 服务的完整框架方案,包含 JWT 实现和完整代码:

1. 环境准备

composer create-project --prefer-dist yiisoft/yii2-app-basic yii2-api
cd yii2-api

2. 安装必要扩展

composer require firebase/php-jwt
composer require yiisoft/yii2-faker

3. 数据库配置 (config/db.php)

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=yii2_api',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
];

4. 用户模型 (models/User.php)

<?php
namespace app\models;

use Yii;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class User extends ActiveRecord implements IdentityInterface
{
    const STATUS_ACTIVE = 10;
    
    public static function tableName()
    {
        return '{{%user}}';
    }

    public function rules()
    {
        return [
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE]],
        ];
    }

    // 实现 IdentityInterface 方法
    public static function findIdentity($id)
    {
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
    }

    public static function findIdentityByAccessToken($token, $type = null)
    {
        try {
            $secret = Yii::$app->params['jwtSecret'];
            $decoded = JWT::decode($token, new Key($secret, 'HS256'));
            return static::findOne(['id' => $decoded->sub, 'status' => self::STATUS_ACTIVE]);
        } catch (\Exception $e) {
            return null;
        }
    }

    public function getId()
    {
        return $this->id;
    }

    public function getAuthKey()
    {
        return null; // 不使用 cookie 登录
    }

    public function validateAuthKey($authKey)
    {
        return false; // 不使用 cookie 登录
    }

    // 生成 JWT Token
    public function generateJwt()
    {
        $secret = Yii::$app->params['jwtSecret'];
        $currentTime = time();
        
        $payload = [
            'iss' => 'yii2-api-server', // 签发者
            'aud' => 'api-client',      // 接收方
            'iat' => $currentTime,      // 签发时间
            'exp' => $currentTime + 86400, // 过期时间 (24小时)
            'sub' => $this->id,         // 用户ID
        ];
        
        return JWT::encode($payload, $secret, 'HS256');
    }

    // 验证密码
    public function validatePassword($password)
    {
        return Yii::$app->security->validatePassword($password, $this->password_hash);
    }

    // 设置密码
    public function setPassword($password)
    {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }
}

5. 登录表单模型 (models/LoginForm.php)

<?php
namespace app\models;

use yii\base\Model;

class LoginForm extends Model
{
    public $username;
    public $password;
    public $rememberMe = true;

    private $_user;

    public function rules()
    {
        return [
            [['username', 'password'], 'required'],
            ['rememberMe', 'boolean'],
            ['password', 'validatePassword'],
        ];
    }

    public function validatePassword($attribute)
    {
        if (!$this->hasErrors()) {
            $user = $this->getUser();
            if (!$user || !$user->validatePassword($this->password)) {
                $this->addError($attribute, '用户名或密码错误');
            }
        }
    }

    public function login()
    {
        if ($this->validate()) {
            return $this->getUser()->generateJwt();
        }
        return false;
    }

    protected function getUser()
    {
        if ($this->_user === null) {
            $this->_user = User::findByUsername($this->username);
        }
        return $this->_user;
    }
}

6. API 控制器基类 (controllers/ApiController.php)

<?php
namespace app\controllers;

use yii\rest\Controller;
use yii\filters\auth\HttpBearerAuth;
use yii\web\UnauthorizedHttpException;

class ApiController extends Controller
{
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        
        // 启用 Bearer Token 认证
        $behaviors['authenticator'] = [
            'class' => HttpBearerAuth::className(),
            'optional' => $this->authOptional(), // 排除不需要认证的方法
        ];
        
        return $behaviors;
    }
    
    protected function authOptional()
    {
        return [];
    }
    
    // 认证失败处理
    public function beforeAction($action)
    {
        if (!parent::beforeAction($action)) {
            return false;
        }
        
        if (Yii::$app->user->isGuest && !in_array($action->id, $this->authOptional())) {
            throw new UnauthorizedHttpException('请提供有效的认证令牌');
        }
        
        return true;
    }
}

7. 认证控制器 (controllers/AuthController.php)

<?php
namespace app\controllers;

use app\models\LoginForm;
use yii\rest\Controller;
use yii\web\ServerErrorHttpException;

class AuthController extends Controller
{
    public function actionLogin()
    {
        $model = new LoginForm();
        $model->load(Yii::$app->request->post(), '');
        
        if ($token = $model->login()) {
            return ['token' => $token];
        } elseif ($model->hasErrors()) {
            return $model;
        } else {
            throw new ServerErrorHttpException('登录失败,请稍后重试');
        }
    }
}

8. 受保护 API 示例 (controllers/UserController.php)

<?php
namespace app\controllers;

class UserController extends ApiController
{
    protected function authOptional()
    {
        return []; // 所有操作都需要认证
    }
    
    public function actionProfile()
    {
        $user = Yii::$app->user->identity;
        return [
            'id' => $user->id,
            'username' => $user->username,
            'email' => $user->email,
            'created_at' => date('Y-m-d H:i:s', $user->created_at),
        ];
    }
    
    public function actionSecureData()
    {
        return [
            'message' => '这是受保护的API数据',
            'timestamp' => time(),
            'user_id' => Yii::$app->user->id
        ];
    }
}

9. 配置参数 (config/params.php)

return [
    'adminEmail' => 'admin@example.com',
    'jwtSecret' => 'your-secret-key-here', // 替换为强密钥
];

10. 配置 URL 规则 (config/web.php)

'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
        'POST /auth/login' => 'auth/login',
        
        'GET /user/profile' => 'user/profile',
        'GET /secure-data' => 'user/secure-data',
        
        // RESTful API 路由示例
        ['class' => 'yii\rest\UrlRule', 'controller' => 'api'],
    ],
],

11. 数据库迁移

创建用户表迁移:

yii migrate/create create_user_table
// migrations/mxxxxxx_xxxxxx_create_user_table.php
public function safeUp()
{
    $this->createTable('{{%user}}', [
        'id' => $this->primaryKey(),
        'username' => $this->string(255)->notNull()->unique(),
        'email' => $this->string(255)->notNull()->unique(),
        'password_hash' => $this->string(255)->notNull(),
        'status' => $this->smallInteger()->notNull()->defaultValue(10),
        'created_at' => $this->integer()->notNull(),
        'updated_at' => $this->integer()->notNull(),
    ]);
}

public function safeDown()
{
    $this->dropTable('{{%user}}');
}

运行迁移:

yii migrate/up

12. 测试用户生成 (commands/SeedController.php)

yii migrate/create create_seed_controller
<?php
namespace app\commands;

use yii\console\Controller;
use app\models\User;

class SeedController extends Controller
{
    public function actionIndex()
    {
        $user = new User();
        $user->username = 'testuser';
        $user->email = 'test@example.com';
        $user->setPassword('password123');
        $user->created_at = time();
        $user->updated_at = time();
        
        if ($user->save()) {
            echo "测试用户创建成功\n";
            echo "用户名: testuser\n";
            echo "密码: password123\n";
        } else {
            print_r($user->errors);
        }
    }
}

运行种子:

yii seed

使用示例

1. 获取 Token
curl -X POST http://api.example.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser", "password":"password123"}'

响应:

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."}
2. 访问受保护 API
curl -X GET http://api.example.com/user/profile \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."

响应:

{
    "id": 1,
    "username": "testuser",
    "email": "test@example.com",
    "created_at": "2023-05-15 10:30:00"
}

安全增强建议

  1. HTTPS 强制使用

    // config/web.php
    'components' => [
        'request' => [
            'cookieValidationKey' => 'your-key',
            'enableCsrfValidation' => false, // API 通常禁用 CSRF
            'parsers' => [
                'application/json' => 'yii\web\JsonParser',
            ],
        ],
    ],
    
  2. 速率限制

    // 在控制器中添加
    use yii\filters\RateLimiter;
    
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['rateLimiter'] = [
            'class' => RateLimiter::class,
        ];
        return $behaviors;
    }
    
  3. 刷新令牌机制

    • 实现双令牌系统(access token + refresh token)
    • access token 设置较短有效期(如 30 分钟)
    • 使用 refresh token 获取新 access token
  4. 敏感操作日志

    • 记录所有关键操作(登录、数据修改等)
    • 包含用户 ID、IP 地址和时间戳

这个框架提供了完整的 JWT 认证实现,包含了用户管理、Token 生成与验证、API 保护等核心功能,可以直接作为基础进行扩展开发。

通义千问-回答
实操成功
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰哥技术分享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值