Commit f69a73ba by Qiang Xue

refactored User and Identity classes.

parent 9da81894
...@@ -8,6 +8,35 @@ ...@@ -8,6 +8,35 @@
namespace yii\web; namespace yii\web;
/** /**
* Identity is the interface that should be implemented by a class providing identity information.
*
* This interface can typically be implemented by a user model class. For example, the following
* code shows how to implement this interface by a User ActiveRecord class:
*
* ~~~
* class User extends ActiveRecord implements Identity
* {
* public static function findIdentity($id)
* {
* return static::find($id);
* }
*
* public function getId()
* {
* return $this->id;
* }
*
* public function getAuthKey()
* {
* return $this->authKey;
* }
*
* public function validateAuthKey($authKey)
* {
* return $this->authKey === $authKey;
* }
* }
* ~~~
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -29,8 +58,11 @@ interface Identity ...@@ -29,8 +58,11 @@ interface Identity
public function getId(); public function getId();
/** /**
* Returns a key that can be used to check the validity of a given identity ID. * Returns a key that can be used to check the validity of a given identity ID.
* The space of such keys should be big and random enough to defeat potential identity attacks. *
* The returned key can be a string, an integer, or any serializable data. * The key should be unique for each individual user, and should be persistent
* so that it can be used to check the validity of the user identity.
*
* The space of such keys should be big enough to defeat potential identity attacks.
* *
* This is required if [[User::enableAutoLogin]] is enabled. * This is required if [[User::enableAutoLogin]] is enabled.
* @return string a key that is used to check the validity of a given identity ID. * @return string a key that is used to check the validity of a given identity ID.
......
...@@ -13,7 +13,7 @@ use yii\base\HttpException; ...@@ -13,7 +13,7 @@ use yii\base\HttpException;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
/** /**
* User is an application component that manages the user authentication status. * User is the class for the "user" application component that manages the user authentication status.
* *
* In particular, [[User::isGuest]] returns a value indicating whether the current user is a guest or not. * In particular, [[User::isGuest]] returns a value indicating whether the current user is a guest or not.
* Through methods [[login()]] and [[logout()]], you can change the user authentication status. * Through methods [[login()]] and [[logout()]], you can change the user authentication status.
...@@ -32,15 +32,6 @@ class User extends Component ...@@ -32,15 +32,6 @@ class User extends Component
const EVENT_AFTER_LOGOUT = 'afterLogout'; const EVENT_AFTER_LOGOUT = 'afterLogout';
/** /**
* @var Identity the identity object associated with the currently logged user.
* This property is set automatically be the User component. Do not modify it directly
* unless you understand the consequence. You should normally use [[login()]], [[logout()]],
* or [[switchIdentity()]] to update the identity associated with the current user.
*
* If this property is null, it means the current user is a guest (not authenticated).
*/
public $identity;
/**
* @var string the class name of the [[identity]] object. * @var string the class name of the [[identity]] object.
*/ */
public $identityClass; public $identityClass;
...@@ -65,7 +56,7 @@ class User extends Component ...@@ -65,7 +56,7 @@ class User extends Component
* @var array the configuration of the identity cookie. This property is used only when [[enableAutoLogin]] is true. * @var array the configuration of the identity cookie. This property is used only when [[enableAutoLogin]] is true.
* @see Cookie * @see Cookie
*/ */
public $identityCookie = array('name' => '__identity'); public $identityCookie = array('name' => '__identity', 'httponly' => true);
/** /**
* @var integer the number of seconds in which the user will be logged out automatically if he * @var integer the number of seconds in which the user will be logged out automatically if he
* remains inactive. If this property is not set, the user will be logged out after * remains inactive. If this property is not set, the user will be logged out after
...@@ -112,8 +103,6 @@ class User extends Component ...@@ -112,8 +103,6 @@ class User extends Component
Yii::$app->getSession()->open(); Yii::$app->getSession()->open();
$this->loadIdentity();
$this->renewAuthStatus(); $this->renewAuthStatus();
if ($this->enableAutoLogin) { if ($this->enableAutoLogin) {
...@@ -125,20 +114,44 @@ class User extends Component ...@@ -125,20 +114,44 @@ class User extends Component
} }
} }
private $_identity = false;
/** /**
* Loads the [[identity]] object according to [[id]]. * Returns the identity object associated with the currently logged user.
* @return Identity the identity object associated with the currently logged user.
* Null is returned if the user is not logged in (not authenticated).
* @see login
* @see logout
*/ */
protected function loadIdentity() public function getIdentity()
{ {
if ($this->_identity === false) {
$id = $this->getId(); $id = $this->getId();
if ($id === null) { if ($id === null) {
$this->identity = null; $this->_identity = null;
} else { } else {
/** @var $class Identity */ /** @var $class Identity */
$class = $this->identityClass; $class = $this->identityClass;
$this->identity = $class::findIdentity($id); $this->_identity = $class::findIdentity($id);
} }
} }
return $this->_identity;
}
/**
* Sets the identity object.
* This method should be mainly be used by the User component or its child class
* to maintain the identity object.
*
* You should normally update the user identity via methods [[login()]], [[logout()]]
* or [[switchIdentity()]].
*
* @param Identity $identity the identity object associated with the currently logged user.
*/
public function setIdentity($identity)
{
$this->_identity = $identity;
}
/** /**
* Logs in a user. * Logs in a user.
...@@ -157,10 +170,7 @@ class User extends Component ...@@ -157,10 +170,7 @@ class User extends Component
public function login($identity, $duration = 0) public function login($identity, $duration = 0)
{ {
if ($this->beforeLogin($identity, false)) { if ($this->beforeLogin($identity, false)) {
$this->switchIdentity($identity); $this->switchIdentity($identity, $duration);
if ($duration > 0 && $this->enableAutoLogin) {
$this->sendIdentityCookie($identity, $duration);
}
$this->afterLogin($identity, false); $this->afterLogin($identity, false);
} }
return !$this->getIsGuest(); return !$this->getIsGuest();
...@@ -185,10 +195,7 @@ class User extends Component ...@@ -185,10 +195,7 @@ class User extends Component
$identity = $class::findIdentity($id); $identity = $class::findIdentity($id);
if ($identity !== null && $identity->validateAuthKey($authKey)) { if ($identity !== null && $identity->validateAuthKey($authKey)) {
if ($this->beforeLogin($identity, true)) { if ($this->beforeLogin($identity, true)) {
$this->switchIdentity($identity); $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
if ($this->autoRenewCookie) {
$this->sendIdentityCookie($identity, $duration);
}
$this->afterLogin($identity, true); $this->afterLogin($identity, true);
} }
} elseif ($identity !== null) { } elseif ($identity !== null) {
...@@ -206,12 +213,9 @@ class User extends Component ...@@ -206,12 +213,9 @@ class User extends Component
*/ */
public function logout($destroySession = true) public function logout($destroySession = true)
{ {
$identity = $this->identity; $identity = $this->getIdentity();
if ($identity !== null && $this->beforeLogout($identity)) { if ($identity !== null && $this->beforeLogout($identity)) {
$this->switchIdentity(null); $this->switchIdentity(null);
if ($this->enableAutoLogin) {
Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
}
if ($destroySession) { if ($destroySession) {
Yii::$app->getSession()->destroy(); Yii::$app->getSession()->destroy();
} }
...@@ -225,7 +229,7 @@ class User extends Component ...@@ -225,7 +229,7 @@ class User extends Component
*/ */
public function getIsGuest() public function getIsGuest()
{ {
return $this->identity === null; return $this->getIdentity() === null;
} }
/** /**
...@@ -238,14 +242,6 @@ class User extends Component ...@@ -238,14 +242,6 @@ class User extends Component
} }
/** /**
* @param string|integer $value the unique identifier for the user. If null, it means the user is a guest.
*/
public function setId($value)
{
Yii::$app->getSession()->set($this->idVar, $value);
}
/**
* Returns the URL that the user should be redirected to after successful login. * Returns the URL that the user should be redirected to after successful login.
* This property is usually used by the login action. If the login is successful, * This property is usually used by the login action. If the login is successful,
* the action should read this property and use it to redirect the user browser. * the action should read this property and use it to redirect the user browser.
...@@ -400,24 +396,37 @@ class User extends Component ...@@ -400,24 +396,37 @@ class User extends Component
} }
/** /**
* Changes the current user with the specified identity information. * Switches to a new identity for the current user.
* This method is called by [[login()]] and [[loginByCookie()]] *
* when the current user needs to be associated with the corresponding * This method will save necessary session information to keep track of the user authentication status.
* identity information. * If `$duration` is provided, it will also send out appropriate identity cookie
* to support cookie-based login.
*
* This method is mainly called by [[login()]], [[logout()]] and [[loginByCookie()]]
* when the current user needs to be associated with the corresponding identity information.
*
* @param Identity $identity the identity information to be associated with the current user. * @param Identity $identity the identity information to be associated with the current user.
* If null, it means switching to be a guest.
* @param integer $duration number of seconds that the user can remain in logged-in status.
* This parameter is used only when `$identity` is not null.
*/ */
protected function switchIdentity($identity) public function switchIdentity($identity, $duration = 0)
{ {
Yii::$app->getSession()->regenerateID(true);
$this->identity = $identity;
$session = Yii::$app->getSession(); $session = Yii::$app->getSession();
$session->regenerateID(true);
$this->setIdentity($identity);
$session->remove($this->idVar); $session->remove($this->idVar);
$session->remove($this->authTimeoutVar); $session->remove($this->authTimeoutVar);
if ($identity instanceof Identity) { if ($identity instanceof Identity) {
$this->setId($identity->getId()); $session->set($this->idVar, $identity->getId());
if ($this->authTimeout !== null) { if ($this->authTimeout !== null) {
Yii::$app->getSession()->set($this->authTimeoutVar, time() + $this->authTimeout); $session->set($this->authTimeoutVar, time() + $this->authTimeout);
} }
if ($duration > 0 && $this->enableAutoLogin) {
$this->sendIdentityCookie($identity, $duration);
}
} elseif ($this->enableAutoLogin) {
Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
} }
} }
...@@ -429,7 +438,7 @@ class User extends Component ...@@ -429,7 +438,7 @@ class User extends Component
*/ */
protected function renewAuthStatus() protected function renewAuthStatus()
{ {
if ($this->authTimeout !== null && $this->identity !== null) { if ($this->authTimeout !== null && !$this->getIsGuest()) {
$expire = Yii::$app->getSession()->get($this->authTimeoutVar); $expire = Yii::$app->getSession()->get($this->authTimeoutVar);
if ($expire !== null && $expire < time()) { if ($expire !== null && $expire < time()) {
$this->logout(false); $this->logout(false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment