此解决方案添加到 SecurityComponent。它应该可以工作,但如果同时设置了 requireSecure 和 requireNonSecure,则存在重定向循环的风险。
安全加组件:
class SecurityPlusComponent extends SecurityComponent {
/**
* List of actions that do not require an SSL-secured connection
*
* @var array
* @access public
* @see SecurityPlusComponent::requireNonSecure()
*/
var $requireSecure = array();
/**
* Component startup. All security checking happens here.
*
* @param object $controller Instantiating controller
* @access public
*/
function startup(&$controller) {
$this->_action = strtolower($controller->action);
$this->_methodsRequired($controller);
$this->_secureRequired($controller);
$this->_nonSecureRequired($controller);
$this->_authRequired($controller);
$this->_loginRequired($controller);
$isPost = ($this->RequestHandler->isPost() || $this->RequestHandler->isPut());
$isRequestAction = (
!isset($controller->params['requested']) ||
$controller->params['requested'] != 1
);
if ($isPost && $isRequestAction && $this->validatePost) {
if ($this->_validatePost($controller) === false) {
if (!$this->blackHole($controller, 'auth')) {
return null;
}
}
}
$this->_generateToken($controller);
}
function requireNonSecure() {
$this->_requireMethod('NonSecure', func_get_args());
}
/**
* Check if access requires non secure connection (http)
*
* @param object $controller Instantiating controller
* @return bool true if secure connection required
* @access protected
*/
function _nonSecureRequired(&$controller) {
if (is_array($this->requireNonSecure) && !empty($this->requireNonSecure)) {
$requireNonSecure = array_map('strtolower', $this->requireNonSecure);
if (in_array($this->_action, $requireNonSecure) || $this->requireNonSecure == array('*')) {
if ($this->RequestHandler->isSSL()) {
if (!$this->blackHole($controller, 'nonSecure')) {
return null;
}
}
}
}
return true;
}
}
修改 app_controller forceSSL 函数:
function securityBlackhole($type) {
$redirect = '';
if (!empty($this->params['url']['redirect'])) {
$redirect = '?redirect=' . $this->params['url']['redirect'];
}
// Force http (non-SSL)
if($type == 'nonSecure') {
$this->redirect('http://' . rtrim(env('SERVER_NAME'), '/') . $this->here . $redirect);
// Force https (SSL)
} else {
$this->redirect('https://' . rtrim(env('SERVER_NAME'), '/') . $this->here . $redirect);
}
}
在控制器中会这样调用:
function beforeFilter() {
parent::beforeFilter();
$this->SecurityPlus->validatePost = false; // disable CSRF protection
$this->SecurityPlus->blackHoleCallback = 'securityBlackhole';
$this->SecurityPlus->requireSecure('pay', 'index');
$this->SecurityPlus->requireNonSecure('video');
$this->Auth->allow('index');
}