diff options
author | xue <> | 2007-09-26 13:15:56 +0000 |
---|---|---|
committer | xue <> | 2007-09-26 13:15:56 +0000 |
commit | cb62a8b25b67f4c23148efe5d9e93278651d1901 (patch) | |
tree | 4dec8d359fe2b42965ab370f590094ffd1bc5c36 | |
parent | 75293bddc7faea69021f5e29ac9e4df3f04c4f36 (diff) |
added support to remember login.
-rw-r--r-- | HISTORY | 1 | ||||
-rw-r--r-- | UPGRADE | 7 | ||||
-rw-r--r-- | demos/quickstart/protected/pages/Advanced/Auth.page | 42 | ||||
-rw-r--r-- | demos/quickstart/protected/pages/GettingStarted/NewFeatures.page | 1 | ||||
-rw-r--r-- | framework/Security/IUserManager.php | 13 | ||||
-rw-r--r-- | framework/Security/TAuthManager.php | 79 | ||||
-rw-r--r-- | framework/Security/TDbUserManager.php | 66 | ||||
-rw-r--r-- | framework/Security/TUserManager.php | 37 | ||||
-rw-r--r-- | framework/TApplication.php | 4 | ||||
-rw-r--r-- | framework/Web/THttpRequest.php | 2 |
10 files changed, 241 insertions, 11 deletions
@@ -21,6 +21,7 @@ ENH: Ticket#681 - TUrlMapping can construct custom URLs now (Qiang) ENH: Ticket#692,700 - Added support to wildcard in pages configuration; added IP filters in auth rules. (Qiang) ENH: Added THead requirement check (Qiang) ENH: Added TOutputCache.CacheTime (Qiang) +ENH: Added "remember login" support to TAuthManager and the related modules/classes (Qiang) CHG: Ticket#685 - Slashes and backslashes mixup in PradoBase (Qiang) CHG: Ticket#705 - TImage will not set border style by default (Qiang) CHG: GeSHi is replaced with Text_Highlighter (Christophe) @@ -11,10 +11,15 @@ for both A and B. Upgrading from v3.1.0
---------------------
-- IFeedContentProvider adds a new method getContentType(). This affects any
+- IFeedContentProvider adds a new method: getContentType(). This affects any
class implementing this interface.
- TUrlMapping now only uses the PATH_INFO part of URL for matching, and the matching
is for the whole PATH_INFO.
+- IUserManager adds two new methods: getUserFromCookie() and saveUserToCookie().
+ This affects classes that implements this interface and does not extend from
+ TUserManager.
+- The order of application lifecycles is changed. The loadState and loadStateComplete
+ are moved to right after onBeginRequest.
Upgrading from v3.1b
--------------------
diff --git a/demos/quickstart/protected/pages/Advanced/Auth.page b/demos/quickstart/protected/pages/Advanced/Auth.page index 531b8bdf..e0cbcaef 100644 --- a/demos/quickstart/protected/pages/Advanced/Auth.page +++ b/demos/quickstart/protected/pages/Advanced/Auth.page @@ -124,5 +124,47 @@ In the above, <tt>UserClass</tt> specifies what class will be used to create use <p id="720566" class="block-content">
The user class has to implement the two abstract methods in <tt>TDbUser</tt>: <tt>validateUser()</tt> and <tt>createUser()</tt>. Since user account information is stored in a database, the user class may make use of its <tt>DbConnection</tt> property to reach the database.
</p>
+<com:SinceVersion Version="3.1.1" />
+<p id="720567" class="block-content">
+Since 3.1.1, <tt>TAuthManager</tt> provides support to allow remembering login. Accordingly, <tt>TDbUser</tt> adds two methods to facilitate the implementation of this feature. In particular, two new methods are introduced: <tt>createUserFromCookie()</tt> and <tt>saveUserToCookie()</tt>. Developers should implement these two methods if remembering login is needed. Below is a sample implementation:
+</p>
+<com:TTextHighlighter Language="php" CssClass="source block-content" id="code5">
+public function createUserFromCookie($cookie)
+{
+ if(($data=$cookie->Value)!=='')
+ {
+ $application=Prado::getApplication();
+ if(($data=$application->SecurityManager->validateData($data))!==false)
+ {
+ $data=unserialize($data);
+ if(is_array($data) && count($data)===3)
+ {
+ list($username,$address,$token)=$data;
+ $sql='SELECT passcode FROM user WHERE LOWER(username)=:username';
+ $command=$this->DbConnection->createCommand($sql);
+ $command->bindValue(':username',strtolower($username));
+ if($token===$command->queryScalar() && $token!==false && $address=$application->Request->UserHostAddress)
+ return $this->createUser($username);
+ }
+ }
+ }
+ return null;
+}
+
+public function saveUserToCookie($cookie)
+{
+ $application=Prado::getApplication();
+ $username=strtolower($this->Name);
+ $address=$application->Request->UserHostAddress;
+ $sql='SELECT passcode FROM user WHERE LOWER(username)=:username';
+ $command=$this->DbConnection->createCommand($sql);
+ $command->bindValue(':username',strtolower($username));
+ $token=$command->queryScalar();
+ $data=array($username,$address,$token);
+ $data=serialize($data);
+ $data=$application->SecurityManager->hashData($data);
+ $cookie->setValue($data);
+}
+</com:TTextHighlighter>
<div class="last-modified">$Id$</div></com:TContent>
\ No newline at end of file diff --git a/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page b/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page index adc19fc7..faf3b9b1 100644 --- a/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page +++ b/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page @@ -17,6 +17,7 @@ This page summarizes the main new features that are introduced in each PRADO rel <li>Added support to TDataGrid to allow grouping consecutive cells with the same content.</li>
<li>Added support to allow configuring page properties and authorization rules using <a href="?page=Configurations.PageConfig">relative page paths</a> in application and page configurations. Added support to allow <a href="?page=Advanced.Auth">authorization</a> based on remote host address.</li>
<li>Added a new page state persister <tt>TCachePageStatePersister</tt>. It allows page state to be stored using a cache module (e.g. TMemCache, TDbCache, etc.)
+<li>Added support to the <a href="?page=Advanced.Auth">auth framework</a> to allow remembering login.</li>
</ul>
<h2 id="8006">Version 3.1.0</h2>
diff --git a/framework/Security/IUserManager.php b/framework/Security/IUserManager.php index 649c41b6..d90450a9 100644 --- a/framework/Security/IUserManager.php +++ b/framework/Security/IUserManager.php @@ -35,6 +35,19 @@ interface IUserManager */
public function getUser($username=null);
/**
+ * Returns a user instance according to auth data stored in a cookie.
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @since 3.1.1
+ */
+ public function getUserFromCookie($cookie);
+ /**
+ * Saves user auth data into a cookie.
+ * @param THttpCookie the cookie to receive the user auth data.
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie);
+ /**
* Validates if the username and password are correct.
* @param string user name
* @param string password
diff --git a/framework/Security/TAuthManager.php b/framework/Security/TAuthManager.php index fcbb64d2..7a6b96a1 100644 --- a/framework/Security/TAuthManager.php +++ b/framework/Security/TAuthManager.php @@ -60,6 +60,14 @@ class TAuthManager extends TModule * @var string the session var name for storing return URL
*/
private $_returnUrlVarName;
+ /**
+ * @var boolean whether to allow auto login (using cookie)
+ */
+ private $_allowAutoLogin=false;
+ /**
+ * @var string variable name used to store user session or cookie
+ */
+ private $_userKey;
/**
* Initializes this module.
@@ -216,6 +224,24 @@ class TAuthManager extends TModule }
/**
+ * @return boolean whether to allow remembering login so that the user logs on automatically next time. Defaults to false.
+ * @since 3.1.1
+ */
+ public function getAllowAutoLogin()
+ {
+ return $this->_allowAutoLogin;
+ }
+
+ /**
+ * @param boolean whether to allow remembering login so that the user logs on automatically next time. Users have to enable cookie to make use of this feature.
+ * @since 3.1.1
+ */
+ public function setAllowAutoLogin($value)
+ {
+ $this->_allowAutoLogin=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
* Performs the real authentication work.
* An OnAuthenticate event will be raised if there is any handler attached to it.
* If the application already has a non-null user, it will return without further authentication.
@@ -227,11 +253,27 @@ class TAuthManager extends TModule {
$application=$this->getApplication();
+ // restoring user info from session
if(($session=$application->getSession())===null)
throw new TConfigurationException('authmanager_session_required');
$session->open();
- $sessionInfo=$session->itemAt($this->generateUserSessionKey());
+ $sessionInfo=$session->itemAt($this->getUserKey());
$user=$this->_userManager->getUser(null)->loadFromString($sessionInfo);
+
+ // try authenticating through cookie if possible
+ if($this->getAllowAutoLogin() && $user->getIsGuest())
+ {
+ $cookie=$this->getRequest()->getCookies()->itemAt($this->getUserKey());
+ if($cookie instanceof THttpCookie)
+ {
+ if(($user2=$this->_userManager->getUserFromCookie($cookie))!==null)
+ {
+ $user=$user2;
+ $this->updateSessionUser($user);
+ }
+ }
+ }
+
$application->setUser($user);
// event handler gets a chance to do further auth work
@@ -259,9 +301,21 @@ class TAuthManager extends TModule }
/**
+ * @return string a unique variable name for storing user session/cookie data
+ * @since 3.1.1
+ */
+ public function getUserKey()
+ {
+ if($this->_userKey===null)
+ $this->_userKey=$this->generateUserKey();
+ return $this->_userKey;
+ }
+
+ /**
* @return string a key used to store user information in session
+ * @since 3.1.1
*/
- protected function generateUserSessionKey()
+ protected function generateUserKey()
{
return md5($this->getApplication()->getUniqueID().'prado:user');
}
@@ -278,7 +332,7 @@ class TAuthManager extends TModule if(($session=$this->getSession())===null)
throw new TConfigurationException('authmanager_session_required');
else
- $session->add($this->generateUserSessionKey(),$user->saveToString());
+ $session->add($this->getUserKey(),$user->saveToString());
}
}
@@ -288,15 +342,24 @@ class TAuthManager extends TModule * If yes, a user object will be created for the application.
* @param string username
* @param string password
+ * @param integer number of seconds that automatic login will remain effective. If 0, it means user logs out when session ends. This parameter is added since 3.1.1.
* @return boolean if login is successful
*/
- public function login($username,$password)
+ public function login($username,$password,$expire=0)
{
if($this->_userManager->validateUser($username,$password))
{
$user=$this->_userManager->getUser($username);
$this->updateSessionUser($user);
$this->getApplication()->setUser($user);
+
+ if($expire>0)
+ {
+ $cookie=new THttpCookie($this->getUserKey(),'');
+ $cookie->setExpire(time()+$expire);
+ $this->_userManager->saveUserToCookie($cookie);
+ $this->getResponse()->getCookies()->add($cookie);
+ }
return true;
}
else
@@ -312,10 +375,12 @@ class TAuthManager extends TModule {
if(($session=$this->getSession())===null)
throw new TConfigurationException('authmanager_session_required');
- else
+ $this->getApplication()->getUser()->setIsGuest(true);
+ $session->destroy();
+ if($this->getAllowAutoLogin())
{
- $this->getApplication()->getUser()->setIsGuest(true);
- $session->destroy();
+ $cookie=new THttpCookie($this->getUserKey(),'');
+ $this->getResponse()->getCookies()->add($cookie);
}
}
}
diff --git a/framework/Security/TDbUserManager.php b/framework/Security/TDbUserManager.php index a2f30642..35cf4fd7 100644 --- a/framework/Security/TDbUserManager.php +++ b/framework/Security/TDbUserManager.php @@ -155,7 +155,10 @@ class TDbUserManager extends TModule implements IUserManager public function getDbConnection()
{
if($this->_conn===null)
+ {
$this->_conn=$this->createDbConnection($this->_connID);
+ $this->_conn->setActive(true);
+ }
return $this->_conn;
}
@@ -178,6 +181,29 @@ class TDbUserManager extends TModule implements IUserManager else
throw new TConfigurationException('dbusermanager_connectionid_required');
}
+
+ /**
+ * Returns a user instance according to auth data stored in a cookie.
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TDbUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @since 3.1.1
+ */
+ public function getUserFromCookie($cookie)
+ {
+ return $this->_userFactory->createUserFromCookie($cookie);
+ }
+
+ /**
+ * Saves user auth data into a cookie.
+ * @param THttpCookie the cookie to receive the user auth data.
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie)
+ {
+ $user=$this->getApplication()->getUser();
+ if($user instanceof TDbUser)
+ $user->saveUserToCookie($cookie);
+ }
}
@@ -250,6 +276,46 @@ abstract class TDbUser extends TUser * @return TDbUser the newly created and initialized user instance
*/
abstract public function createUser($username);
+
+ /**
+ * Creates a new user instance given the cookie containing auth data.
+ *
+ * This method is invoked when {@link TAuthManager::setAllowAutoLogin AllowAutoLogin} is set true.
+ * The default implementation simply returns null, meaning no user instance can be created
+ * from the given cookie.
+ *
+ * If you want to support automatic login (remember login), you should override this method.
+ * Typically, you obtain the username and a unique token from the cookie's value.
+ * You then verify the token is valid and use the username to create a user instance.
+ *
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TDbUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @see saveUserToCookie
+ * @since 3.1.1
+ */
+ public function createUserFromCookie($cookie)
+ {
+ return null;
+ }
+
+ /**
+ * Saves necessary auth data into a cookie.
+ * This method is invoked when {@link TAuthManager::rememberLogin} is invoked.
+ * The default implementation does nothing, meaning auth data is not stored in the cookie
+ * (and thus automatic login is not supported.)
+ *
+ * If you want to support automatic login (remember login), you should override this method.
+ * Typically, you generate a unique token according to the current login information
+ * and save it together with the username in the cookie's value.
+ * You should avoid revealing the password in the generated token.
+ *
+ * @param THttpCookie the cookie to store the user auth information
+ * @see createUserFromCookie
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie)
+ {
+ }
}
?>
\ No newline at end of file diff --git a/framework/Security/TUserManager.php b/framework/Security/TUserManager.php index 28651de8..f6aee767 100644 --- a/framework/Security/TUserManager.php +++ b/framework/Security/TUserManager.php @@ -251,6 +251,43 @@ class TUserManager extends TModule implements IUserManager }
/**
+ * Returns a user instance according to auth data stored in a cookie.
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @since 3.1.1
+ */
+ public function getUserFromCookie($cookie)
+ {
+ if(($data=$cookie->getValue())!=='')
+ {
+ $data=unserialize($data);
+ if(is_array($data) && count($data)===2)
+ {
+ list($username,$token)=$data;
+ if(isset($this->_users[$username]) && $token===md5($username.$this->_users[$username]))
+ return $this->getUser($username);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Saves user auth data into a cookie.
+ * @param THttpCookie the cookie to receive the user auth data.
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie)
+ {
+ $user=$this->getApplication()->getUser();
+ $username=strtolower($user->getName());
+ if(isset($this->_users[$username]))
+ {
+ $data=array($username,md5($username.$this->_users[$username]));
+ $cookie->setValue(serialize($data));
+ }
+ }
+
+ /**
* Sets a user as a guest.
* User name is changed as guest name, and roles are emptied.
* @param TUser the user to be changed to a guest.
diff --git a/framework/TApplication.php b/framework/TApplication.php index 3aa2cec1..a0239072 100644 --- a/framework/TApplication.php +++ b/framework/TApplication.php @@ -150,12 +150,12 @@ class TApplication extends TComponent */ private static $_steps=array( 'onBeginRequest', + 'onLoadState', + 'onLoadStateComplete', 'onAuthentication', 'onAuthenticationComplete', 'onAuthorization', 'onAuthorizationComplete', - 'onLoadState', - 'onLoadStateComplete', 'onPreRunService', 'runService', 'onSaveState', diff --git a/framework/Web/THttpRequest.php b/framework/Web/THttpRequest.php index a9e5fe68..ca7780cd 100644 --- a/framework/Web/THttpRequest.php +++ b/framework/Web/THttpRequest.php @@ -911,7 +911,7 @@ class THttpCookie extends TComponent /** * @var string value of the cookie */ - private $_value=0; + private $_value=''; /** * @var integer expire of the cookie */ |