|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- <?php
-
-
- namespace yii\web;
-
- use Yii;
- use yii\base\Component;
- use yii\base\InvalidConfigException;
- use yii\base\InvalidValueException;
- use yii\rbac\CheckAccessInterface;
-
-
- class User extends Component
- {
- const EVENT_BEFORE_LOGIN = 'beforeLogin';
- const EVENT_AFTER_LOGIN = 'afterLogin';
- const EVENT_BEFORE_LOGOUT = 'beforeLogout';
- const EVENT_AFTER_LOGOUT = 'afterLogout';
-
-
-
- public $identityClass;
-
-
- public $enableAutoLogin = false;
-
-
- public $enableSession = true;
-
-
- public $loginUrl = ['site/login'];
-
-
- public $identityCookie = ['name' => '_identity', 'httpOnly' => true];
-
-
- public $authTimeout;
-
-
- public $accessChecker;
-
-
- public $absoluteAuthTimeout;
-
-
- public $autoRenewCookie = true;
-
-
- public $idParam = '__id';
-
-
- public $authTimeoutParam = '__expire';
-
-
- public $absoluteAuthTimeoutParam = '__absoluteExpire';
-
-
- public $returnUrlParam = '__returnUrl';
-
-
- public $acceptableRedirectTypes = ['text/html', 'application/xhtml+xml'];
-
- private $_access = [];
-
-
-
-
- public function init()
- {
- parent::init();
-
- if ($this->identityClass === null) {
- throw new InvalidConfigException('User::identityClass must be set.');
- }
- if ($this->enableAutoLogin && !isset($this->identityCookie['name'])) {
- throw new InvalidConfigException('User::identityCookie must contain the "name" element.');
- }
- }
-
- private $_identity = false;
-
-
-
- public function getIdentity($autoRenew = true)
- {
- if ($this->_identity === false) {
- if ($this->enableSession && $autoRenew) {
- $this->_identity = null;
- $this->renewAuthStatus();
- } else {
- return null;
- }
- }
-
- return $this->_identity;
- }
-
-
-
- public function setIdentity($identity)
- {
- if ($identity instanceof IdentityInterface) {
- $this->_identity = $identity;
- $this->_access = [];
- } elseif ($identity === null) {
- $this->_identity = null;
- } else {
- throw new InvalidValueException('The identity object must implement IdentityInterface.');
- }
- }
-
-
-
- public function login(IdentityInterface $identity, $duration = 0)
- {
- if ($this->beforeLogin($identity, false, $duration)) {
- $this->switchIdentity($identity, $duration);
- $id = $identity->getId();
- $ip = Yii::$app->getRequest()->getUserIP();
- if ($this->enableSession) {
- $log = "User '$id' logged in from $ip with duration $duration.";
- } else {
- $log = "User '$id' logged in from $ip. Session not enabled.";
- }
- Yii::info($log, __METHOD__);
- $this->afterLogin($identity, false, $duration);
- }
-
- return !$this->getIsGuest();
- }
-
-
-
- public function loginByAccessToken($token, $type = null)
- {
-
- $class = $this->identityClass;
- $identity = $class::findIdentityByAccessToken($token, $type);
- if ($identity && $this->login($identity)) {
- return $identity;
- } else {
- return null;
- }
- }
-
-
-
- protected function loginByCookie()
- {
- $data = $this->getIdentityAndDurationFromCookie();
- if (isset($data['identity'], $data['duration'])) {
- $identity = $data['identity'];
- $duration = $data['duration'];
- if ($this->beforeLogin($identity, true, $duration)) {
- $this->switchIdentity($identity, $this->autoRenewCookie ? $duration : 0);
- $id = $identity->getId();
- $ip = Yii::$app->getRequest()->getUserIP();
- Yii::info("User '$id' logged in from $ip via cookie.", __METHOD__);
- $this->afterLogin($identity, true, $duration);
- }
- }
- }
-
-
-
- public function logout($destroySession = true)
- {
- $identity = $this->getIdentity();
- if ($identity !== null && $this->beforeLogout($identity)) {
- $this->switchIdentity(null);
- $id = $identity->getId();
- $ip = Yii::$app->getRequest()->getUserIP();
- Yii::info("User '$id' logged out from $ip.", __METHOD__);
- if ($destroySession && $this->enableSession) {
- Yii::$app->getSession()->destroy();
- }
- $this->afterLogout($identity);
- }
-
- return $this->getIsGuest();
- }
-
-
-
- public function getIsGuest()
- {
- return $this->getIdentity() === null;
- }
-
-
-
- public function getId()
- {
- $identity = $this->getIdentity();
-
- return $identity !== null ? $identity->getId() : null;
- }
-
-
-
- public function getReturnUrl($defaultUrl = null)
- {
- $url = Yii::$app->getSession()->get($this->returnUrlParam, $defaultUrl);
- if (is_array($url)) {
- if (isset($url[0])) {
- return Yii::$app->getUrlManager()->createUrl($url);
- } else {
- $url = null;
- }
- }
-
- return $url === null ? Yii::$app->getHomeUrl() : $url;
- }
-
-
-
- public function setReturnUrl($url)
- {
- Yii::$app->getSession()->set($this->returnUrlParam, $url);
- }
-
-
-
- public function loginRequired($checkAjax = true, $checkAcceptHeader = true)
- {
- $request = Yii::$app->getRequest();
- $canRedirect = !$checkAcceptHeader || $this->checkRedirectAcceptable();
- if ($this->enableSession
- && $request->getIsGet()
- && (!$checkAjax || !$request->getIsAjax())
- && $canRedirect
- ) {
- $this->setReturnUrl($request->getUrl());
- }
- if ($this->loginUrl !== null && $canRedirect) {
- $loginUrl = (array) $this->loginUrl;
- if ($loginUrl[0] !== Yii::$app->requestedRoute) {
- return Yii::$app->getResponse()->redirect($this->loginUrl);
- }
- }
- throw new ForbiddenHttpException(Yii::t('yii', 'Login Required'));
- }
-
-
-
- protected function beforeLogin($identity, $cookieBased, $duration)
- {
- $event = new UserEvent([
- 'identity' => $identity,
- 'cookieBased' => $cookieBased,
- 'duration' => $duration,
- ]);
- $this->trigger(self::EVENT_BEFORE_LOGIN, $event);
-
- return $event->isValid;
- }
-
-
-
- protected function afterLogin($identity, $cookieBased, $duration)
- {
- $this->trigger(self::EVENT_AFTER_LOGIN, new UserEvent([
- 'identity' => $identity,
- 'cookieBased' => $cookieBased,
- 'duration' => $duration,
- ]));
- }
-
-
-
- protected function beforeLogout($identity)
- {
- $event = new UserEvent([
- 'identity' => $identity,
- ]);
- $this->trigger(self::EVENT_BEFORE_LOGOUT, $event);
-
- return $event->isValid;
- }
-
-
-
- protected function afterLogout($identity)
- {
- $this->trigger(self::EVENT_AFTER_LOGOUT, new UserEvent([
- 'identity' => $identity,
- ]));
- }
-
-
-
- protected function renewIdentityCookie()
- {
- $name = $this->identityCookie['name'];
- $value = Yii::$app->getRequest()->getCookies()->getValue($name);
- if ($value !== null) {
- $data = json_decode($value, true);
- if (is_array($data) && isset($data[2])) {
- $cookie = new Cookie($this->identityCookie);
- $cookie->value = $value;
- $cookie->expire = time() + (int) $data[2];
- Yii::$app->getResponse()->getCookies()->add($cookie);
- }
- }
- }
-
-
-
- protected function sendIdentityCookie($identity, $duration)
- {
- $cookie = new Cookie($this->identityCookie);
- $cookie->value = json_encode([
- $identity->getId(),
- $identity->getAuthKey(),
- $duration,
- ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
- $cookie->expire = time() + $duration;
- Yii::$app->getResponse()->getCookies()->add($cookie);
- }
-
-
-
- protected function getIdentityAndDurationFromCookie()
- {
- $value = Yii::$app->getRequest()->getCookies()->getValue($this->identityCookie['name']);
- if ($value === null) {
- return null;
- }
- $data = json_decode($value, true);
- if (count($data) == 3) {
- list ($id, $authKey, $duration) = $data;
-
- $class = $this->identityClass;
- $identity = $class::findIdentity($id);
- if ($identity !== null) {
- if (!$identity instanceof IdentityInterface) {
- throw new InvalidValueException("$class::findIdentity() must return an object implementing IdentityInterface.");
- } elseif (!$identity->validateAuthKey($authKey)) {
- Yii::warning("Invalid auth key attempted for user '$id': $authKey", __METHOD__);
- } else {
- return ['identity' => $identity, 'duration' => $duration];
- }
- }
- }
- $this->removeIdentityCookie();
- return null;
- }
-
-
-
- protected function removeIdentityCookie()
- {
- Yii::$app->getResponse()->getCookies()->remove(new Cookie($this->identityCookie));
- }
-
-
-
- public function switchIdentity($identity, $duration = 0)
- {
- $this->setIdentity($identity);
-
- if (!$this->enableSession) {
- return;
- }
-
-
- if ($this->enableAutoLogin) {
- $this->removeIdentityCookie();
- }
-
- $session = Yii::$app->getSession();
- if (!YII_ENV_TEST) {
- $session->regenerateID(true);
- }
- $session->remove($this->idParam);
- $session->remove($this->authTimeoutParam);
-
- if ($identity) {
- $session->set($this->idParam, $identity->getId());
- if ($this->authTimeout !== null) {
- $session->set($this->authTimeoutParam, time() + $this->authTimeout);
- }
- if ($this->absoluteAuthTimeout !== null) {
- $session->set($this->absoluteAuthTimeoutParam, time() + $this->absoluteAuthTimeout);
- }
- if ($duration > 0 && $this->enableAutoLogin) {
- $this->sendIdentityCookie($identity, $duration);
- }
- }
- }
-
-
-
- protected function renewAuthStatus()
- {
- $session = Yii::$app->getSession();
- $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;
-
- if ($id === null) {
- $identity = null;
- } else {
-
- $class = $this->identityClass;
- $identity = $class::findIdentity($id);
- }
-
- $this->setIdentity($identity);
-
- if ($identity !== null && ($this->authTimeout !== null || $this->absoluteAuthTimeout !== null)) {
- $expire = $this->authTimeout !== null ? $session->get($this->authTimeoutParam) : null;
- $expireAbsolute = $this->absoluteAuthTimeout !== null ? $session->get($this->absoluteAuthTimeoutParam) : null;
- if ($expire !== null && $expire < time() || $expireAbsolute !== null && $expireAbsolute < time()) {
- $this->logout(false);
- } elseif ($this->authTimeout !== null) {
- $session->set($this->authTimeoutParam, time() + $this->authTimeout);
- }
- }
-
- if ($this->enableAutoLogin) {
- if ($this->getIsGuest()) {
- $this->loginByCookie();
- } elseif ($this->autoRenewCookie) {
- $this->renewIdentityCookie();
- }
- }
- }
-
-
-
- public function can($permissionName, $params = [], $allowCaching = true)
- {
- if ($allowCaching && empty($params) && isset($this->_access[$permissionName])) {
- return $this->_access[$permissionName];
- }
- if (($accessChecker = $this->getAccessChecker()) === null) {
- return false;
- }
- $access = $accessChecker->checkAccess($this->getId(), $permissionName, $params);
- if ($allowCaching && empty($params)) {
- $this->_access[$permissionName] = $access;
- }
-
- return $access;
- }
-
-
-
- protected function checkRedirectAcceptable()
- {
- $acceptableTypes = Yii::$app->getRequest()->getAcceptableContentTypes();
- if (empty($acceptableTypes) || count($acceptableTypes) === 1 && array_keys($acceptableTypes)[0] === '*/*') {
- return true;
- }
-
- foreach ($acceptableTypes as $type => $params) {
- if (in_array($type, $this->acceptableRedirectTypes, true)) {
- return true;
- }
- }
-
- return false;
- }
-
-
-
- protected function getAuthManager()
- {
- return Yii::$app->getAuthManager();
- }
-
-
-
- protected function getAccessChecker()
- {
- return $this->accessChecker !== null ? $this->accessChecker : $this->getAuthManager();
- }
- }
|