以下是一个基于 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"
}
安全增强建议
-
HTTPS 强制使用:
// config/web.php 'components' => [ 'request' => [ 'cookieValidationKey' => 'your-key', 'enableCsrfValidation' => false, // API 通常禁用 CSRF 'parsers' => [ 'application/json' => 'yii\web\JsonParser', ], ], ],
-
速率限制:
// 在控制器中添加 use yii\filters\RateLimiter; public function behaviors() { $behaviors = parent::behaviors(); $behaviors['rateLimiter'] = [ 'class' => RateLimiter::class, ]; return $behaviors; }
-
刷新令牌机制:
- 实现双令牌系统(access token + refresh token)
- access token 设置较短有效期(如 30 分钟)
- 使用 refresh token 获取新 access token
-
敏感操作日志:
- 记录所有关键操作(登录、数据修改等)
- 包含用户 ID、IP 地址和时间戳
这个框架提供了完整的 JWT 认证实现,包含了用户管理、Token 生成与验证、API 保护等核心功能,可以直接作为基础进行扩展开发。
通义千问-回答
实操成功