当前位置: 首页 > news >正文

对Yii2中开启`authenticator`后出现的跨域问题-修复

针对Yii2中开启authenticator后出现的跨域问题,以下是优化后的解决方案。主要修复点包括正确处理OPTIONS预检请求修复认证器配置优化CORS设置

<?php
namespace app\controllers;use app\models\SystemLog;
use Yii;
use yii\filters\Cors;
use yii\rest\Controller;
use yii\filters\auth\HttpBearerAuth;
use yii\web\UnauthorizedHttpException;class ApiController extends Controller
{// 日志级别常量const LOG_LEVEL_INFO = 'info';const LOG_LEVEL_WARNING = 'warning';const LOG_LEVEL_ERROR = 'error';public function behaviors(){$behaviors = parent::behaviors();// 移除默认的认证器unset($behaviors['authenticator']);// CORS 优先 - 修复关键点:允许Authorization头$behaviors['corsFilter'] = ['class' => Cors::class,'cors' => ['Origin' => Yii::$app->params['allowedOrigins'] ?? ['http://localhost:3002', 'http://api.mfe.local'],'Access-Control-Allow-Credentials' => true,'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],'Access-Control-Request-Headers' => ['*'], // 允许所有头'Access-Control-Expose-Headers' => ['*'],  // 暴露所有头给客户端'Access-Control-Max-Age' => 86400,],];// 认证器配置 - 修复关键点:正确排除OPTIONS$behaviors['authenticator'] = ['class' => HttpBearerAuth::class,'except' => array_merge(['options'], $this->authOptional()),];// 日志过滤器(最后执行)$behaviors['requestLogger'] = new class extends \yii\base\ActionFilter {public function beforeAction($action){if (!Yii::$app->request->isOptions) {Yii::info(['action' => $action->id,'request' => Yii::$app->request->rawBody,'headers' => Yii::$app->request->headers->toArray(),], 'api_requests');}return parent::beforeAction($action);}];return $behaviors;}// 确保OPTIONS方法被排除 - 修复关键点protected function authOptional(){return ['options'];}// 处理OPTIONS请求 - 新增方法public function actionOptions(){Yii::$app->response->statusCode = 200;return [];}// 认证失败处理 - 跳过OPTIONS请求public function beforeAction($action){if (!parent::beforeAction($action)) {return false;}// 关键修复:跳过OPTIONS请求的认证检查if (Yii::$app->request->isOptions) {return true;}if (Yii::$app->user->isGuest && !in_array($action->id, $this->authOptional())) {throw new UnauthorizedHttpException('登录已过期,请重新登录');}return true;}/* 其余方法保持不变(getId, getWid, afterAction, success, error等) */// ...
}

关键修复说明:

  1. CORS配置优化

    'Access-Control-Request-Headers' => ['*'],     // 允许所有请求头
    'Access-Control-Expose-Headers' => ['*'],      // 暴露所有响应头
    

    确保浏览器能传递和处理Authorization

  2. 认证器配置修复

    unset($behaviors['authenticator']); // 移除默认认证器
    $behaviors['authenticator'] = ['except' => array_merge(['options'], $this->authOptional()),
    ];
    

    显式排除OPTIONS请求,避免预检请求被拦截

  3. OPTIONS请求处理

    public function actionOptions()
    {Yii::$app->response->statusCode = 200;return [];
    }
    

    添加专门的OPTIONS处理器返回空响应

  4. 认证检查跳过OPTIONS

    public function beforeAction($action)
    {// ...if (Yii::$app->request->isOptions) {return true; // 直接放行OPTIONS请求}// ...
    }
    
  5. 跨域白名单扩展(可选):
    在配置文件中增加更多允许的源:

    // config/params.php
    return ['allowedOrigins' => ['http://localhost:3002','http://api.mfe.local','https://your-production-domain.com'],
    ];
    

补充建议:

  1. Nginx/Apache配置
    确保服务器配置允许跨域头:

    # Nginx配置示例
    add_header 'Access-Control-Allow-Origin' $http_origin always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' '*' always;
    
  2. 前端Axios配置
    确保请求携带凭证:

    // 前端请求配置
    axios.defaults.withCredentials = true;
    
  3. 测试预检请求
    使用curl测试OPTIONS请求:

    curl -X OPTIONS http://api.mfe.local/api/user/info \-H "Origin: http://localhost:3002" \-H "Access-Control-Request-Method: GET" \-H "Access-Control-Request-Headers: authorization" \-I
    

这些修改确保:

  1. OPTIONS预检请求正确处理
  2. Authorization头能被跨域传递
  3. 认证中间件不会拦截预检请求
  4. 服务器返回正确的CORS响应头

修复后,带Bearer Token的跨域请求流程:

浏览器API服务器OPTIONS预检请求跳过认证检查返回CORS头(200)实际请求(GET/POST...)检查Bearer Token返回数据(200)返回401错误alt[认证成功][认证失败]浏览器API服务器

实测成功
【关键在于】
在这里插入图片描述

在这里插入图片描述

http://www.dtcms.com/a/285490.html

相关文章:

  • .QOI: Lossless Image Compression in O(n) Time
  • 变量命名规则
  • git--gitlab
  • 性能远超Spring Cloud Gateway!Apache ShenYu如何重新定义API网关!
  • 无标记点动捕:如何突破传统娱乐边界,打造沉浸式交互体验
  • 高速公路自动化安全监测主要内容
  • Elasticsearch+Logstash+Filebeat+Kibana部署(单机部署)
  • 在 Jenkins 中使用 SSH 部署密钥
  • JAVA高级第五章,简易超市会员管理系统
  • sqli-labs靶场通关笔记:第29-31关 HTTP参数污染
  • Android 应用保活思路
  • 小红书采集工具:无水印图片一键获取,同步采集笔记与评论
  • 银河麒麟高级服务器V10(ARM)安装人大金仓KingbaseES完整教程
  • 【unitrix】 6.7 基本结构体(types.rs)
  • IDEA插件离线安装
  • Vue3 Anime.js超级炫酷的网页动画库详解
  • 完整的 Meteor NPM 集成
  • 游戏常用运行库合集下载 - 提升游戏与软件体验
  • Nestjs框架: 基于TypeORM的多租户功能集成
  • Linux C 进程间通信基本操作
  • QT Windows 资源管理器的排序规则
  • 通俗易懂:什么是决策树?
  • 禁止拖动视频进度条来保障视频安全?
  • MBIST - Memory BIST会对memory进行清零吗?
  • QGIS二次开发环境搭建(qgis-3.28.6+qt5.15)
  • Telink BLE 低电压检测
  • AI IDE冲击下JetBrains作死,IDEA埋订阅陷阱
  • Redis中字符串类型的实现原理
  • 数据通信与计算机网络——模拟传输
  • websocket案例 599足球比分