I came across this question while working on a Yii website project:
What is the best way to force Yii to serve a page with https?
On a site with a login page, for example, you always want to serve the page over https instead of http. After looking through the docs some, I came up with the following solution. Use a custom CFilter to force https on pages that need to be secured.
If you look at CAccessControlFilter in the documentation, you’ll see that it does something very similar to what I’m trying to do. CAccessControlFilter reads a set of rules from the Controller’s accessRules() method, processes them, and decides to let the request continue or to throw a permissions exception. What I need is an HttpsFilter that checks whether or not the current request is being made securely, and redirect to https if it isn’t. Setting this up will require two steps: writing the filter class, and adding a filter method to the Controller class, and adding the filter to my controllers.
Writing the Filter Class
Here’s the code for HttpFilter.php, which I stuck into my Yii project’s protected/components/ folder:
class HttpsFilter extends CFilter {
protected function preFilter( $filterChain ) {
if ( !Yii::app()->getRequest()->isSecureConnection ) {
# Redirect to the secure version of the page.
$url = 'https://' .
Yii::app()->getRequest()->serverName .
Yii::app()->getRequest()->requestUri;
Yii::app()->request->redirect($url);
return false;
}
return true;
}
}
Some notes:
- HttpFilter inherits from CFilter
- I override the preFilter method of the class. You probably don’t want to override filter() because CFilter may be doing special secret stuff inside.
- preFilter() should return false if the processing of the page should stop, and true if all is well and the processing should continue.
Adding a Filter Method to the Controller Class
If you’re working on a standard Yii set-up, you’ll have a class file Controller.php located in your components directory. This Controller class is the parent class that all of your other controllers inherit from. Since we want the ability to enforce https on any of our pages. So to that end, I’ll add the method filterHttps to the Controller class. I’ll explain why the method has that name in the next section. Here’s my copy of protected/components/Controller.php:
class Controller extends CController
{
public $breadcrumbs=array();
public function filterHttps( $filterChain ) {
$filter = new HttpsFilter;
$filter->filter( $filterChain );
}
}
Here, filterHttps simply creates a new HttpsFilter, and calls filter() on it, which in turn calls the preFilter method we wrote above. Now that we’ve made filterHttps available to our controllers, it’s time to use it.
Adding the Filter to My Controllers
I started this article wanting to make sure that Yii forced my users to view the login page under http, and that’s where I’ll end. In a default set up, the login page is handled by the SiteController class. Here, we can add https checking for the login page by modifying the filters() method of SiteController, so that it reads like this:
public function filters()
{
return array(
'https +login', // Force https, but only on login page
);
}
The filter that we added has two parts. First, is “https”. When this filter is applied, Yii will look for the method filterHttps and call it to apply the filter. This is method we defined in the parent class of SiteController, in the previous section. Second, is “+login”. This tells Yii only to apply the filter for the “login” action, and not for any of the other actions handled by SiteController, like the home page.
It took me a while to figure this out, but when I did, I was happy with how clean the solution seemed. Here’s a link to an article on authentication and authorization in Yii which was pretty helpful.