Yii2 认证实现原理和示例

Posted 小帅豹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Yii2 认证实现原理和示例相关的知识,希望对你有一定的参考价值。

Yii的用户认证分为两个部分,一个是User组件,负责管理用户认证状态的,包括登录,登出,检测当前登录状态等,源文件位于vender/yiisoft/yii2/web/User.php。另一个是实现接口IdentityInterface的模型,同时必须继承ActiveRecord,当用户登录注册时,组件User会通过模型中的接口方法,对用户进行验证。

  对于用户状态切换主要通过switchIdentity方法实现的,比如注册后,用户登录时,会用到User组件中的switchIdentity方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
     * Switches to a new identity for the current user.
     *
     * When [[enableSession]] is true, this method may use session and/or cookie to store the user identity information,
     * according to the value of `$duration`. Please refer to [[login()]] for more details.
     *
     * This method is mainly called by [[login()]], [[logout()]] and [[loginByCookie()]]
     * when the current user needs to be associated with the corresponding identity information.
     *
     * @param IdentityInterface|null $identity the identity information to be associated with the current user.
     * If null, it means switching the current user 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.
     */
    public function switchIdentity($identity$duration = 0)
    {
        $this->setIdentity($identity);
 
        if (!$this->enableSession) {
            return;
        }
 
        /* Ensure any existing identity cookies are removed. */
        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);
            }
        }
    }

  如果写入identity为null,则将用户状态设置为离线,如果不是null,而是模型实例,该方法会将用户模型的id值写入session中,用户打开新页面时,只需下面的方法就可以判断是否已经登录。

1
2
//已登录返回true
Yii::$app->user->isGuest

  访问user组件的isGuest属性,会通过魔术方法,调用User组件中的getIsGuest方法

1
2
3
4
5
6
7
8
9
/**
 * Returns a value indicating whether the user is a guest (not authenticated).
 * @return boolean whether the current user is a guest.
 * @see getIdentity()
 */
public function getIsGuest()
{
    return $this->getIdentity() === null;
}

  方法又调用getIdentity()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * Returns the identity object associated with the currently logged-in user.
 * When [[enableSession]] is true, this method may attempt to read the user\'s authentication data
 * stored in session and reconstruct the corresponding identity object, if it has not done so before.
 * @param boolean $autoRenew whether to automatically renew authentication status if it has not been done so before.
 * This is only useful when [[enableSession]] is true.
 * @return IdentityInterface|null the identity object associated with the currently logged-in user.
 * `null` is returned if the user is not logged in (not authenticated).
 * @see login()
 * @see logout()
 */
public function getIdentity($autoRenew = true)
{
    if ($this->_identity === false) {
        if ($this->enableSession && $autoRenew) {
            $this->_identity = null;
            $this->renewAuthStatus();
        else {
            return null;
        }
    }
 
    return $this->_identity;
}

  当session启用时,通过renewAuthStatus()更新新用户状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
 * Updates the authentication status using the information from session and cookie.
 *
 * This method will try to determine the user identity using the [[idParam]] session variable.
 *
 * If [[authTimeout]] is set, this method will refresh the timer.
 *
 * If the user identity cannot be determined by session, this method will try to [[loginByCookie()|login by cookie]]
 * if [[enableAutoLogin]] is true.
 */
protected function renewAuthStatus()
{
    $session = Yii::$app->getSession();
    $id $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;
 
    if ($id === null) {
        $identity = null;
    else {
        /* @var $class IdentityInterface */
        $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();
        }
    }
}

  该方法主要通过session取出用户id,然后通过id获取用户模型实例,然后使用实例进行登录,和更新认证过期时间。

  下面实现一个常用的用户注册登录功能模块,用户只有登录后才可以进入home页面

  User模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?php
/**
 * Created by PhpStorm.
 * User: zhenbao
 * Date: 16/10/17
 * Time: 下午4:14
 */
 
namespace app\\models;
 
use Yii;
use yii\\web\\IdentityInterface;
use yii\\db\\ActiveRecord;
 
class User extends ActiveRecord implements IdentityInterface
{
    const LOGIN = "login";
    const REGISTER = "register";
 
    public function scenarios()
    {
        return [
            self::LOGIN => [\'username\'\'password\'],
            self::REGISTER => [\'username\'\'password\']
        ];
    }
 
    public static function tableName()
    {
        return "user";
    }
 
    public static function findIdentity($id)
    {
        return static::findOne($id);
    }
 
    public static function findIdentityByAccessToken($token$type = null)
    {
        return static::findOne([\'accessToken\' => $token]);
    }
 
    public function getId()
    {
        return $this -> id;
    }
 
    public function getAuthKey()
    {
        return $this -> authKey;
    }
 
    public function validateAuthKey($authKey)
    {
        return $this -> getAuthKey() === $authKey;
    }
 
    public static function findIdentityByUsername($username)
    {
        return static::findOne([\'username\' => $username]);
    }
 
    public function validatePassword($password)
    {
        return $this -> password === sha1($password);
    }
 
    public function setPassword()
    {
        $this -> password = sha1($this -> password);
        return true;
    }
 
    public function beforeSave($insert)
    {
        if(parent::beforeSave($insert))
        {
            if($this -> isNewRecord)
            {
                $this -> authKey = Yii::$app -> security -> generateRandomString();
            }
            return true;
        }
        return false;
    }
}

  控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php
 
namespace app\\controllers;
 
use Yii;
use yii\\web\\Controller;
use app\\models\\User;
use yii\\web\\Cookie;
 
class UserController extends Controller
{
    /**默认方法为home方法
     * @var string
     */
    public $defaultAction \'home\';
 
    /**用户登录,当已经登录直接跳转home页面,
     * 否则,查看是否有访问accessToken,如果有使用accessToken登录,如果accessToken无效则删除accessToken然后返回到登录界面
     * 如果没有accessToken则使用用户的登录密码登录,验证成功后,查看是否选择了记住我,有则生成accessToken,下次直接使用accessToken登录
     * 登录失败,返回到登录界面重新登录。
     * @return string|\\yii\\web\\Response
     */
    public function actionLogin()
    {

(c)2006-2024 SYSTEM All Rights Reserved IT常识