用户登录 - 自动检测登录

  • 作者:KK

  • 发表日期:2017.01.28


前面提到判断用户登录用Yii::$app->user->isGuest来确定是否登录

但是通常大多数功能都要登录后才使用,那如果每一个站内功能都写这个if判断肯定是不现实

其实大家也能想到一些技巧来实现,比如定义一个控制器基类,在基类的init方法里做isGuest判断,所有控制器继承它就行了


方法1:官方推荐,用访问过滤器来判断

其实这并不是我最推荐的方式,但为了顺利把官方的基础知识学一下,我觉得有必要掌握一下这招

官方在过滤器封装好了一套登录校验逻辑,我们可以直接拿来配置一下就能用上,并且对于需求不断变化的应用来说,用这个比较好扩展

还记得过滤器这篇文章里提到的过滤器吧,在做登录授权的时候就是使用官方自带的yii\filters\AccessControl这个“访问控制”过滤器

好了我们假设有个控制器要用,那就在这个控制器里重写父类的behaviors方法:

public function behaviors(){
	return [
		'access' => [
			'class' => 'yii\filters\AccessControl',
			'rules' => [ //检测规则
				[ //第1条规则
					'roles' => ['@'], //角色集合,@表示登录用户
					'allow' => true, //是否允许访问
				],
				
				[ //第2条规则
					'actions' => ['login', 'register'], //针对本控制器的哪些方法ID生效,这两个ID就是针对actionLogin和actionRegister两个方法生效
					'roles' => ['?'], //? 表示未登录用户
					'allow' => true, //允许未登录用户访问
				],
			],
		],
	];
}

配置好后未登录状态下可以运行控制器的login和register方法,不能运行其它方法,会返回HTTP 403,这是访问控制过滤器的基本使用,晚点再慢慢深入掌握它


  • 访问过滤器规则的封装

    虽然重写behaviors方法使用过滤器就能实现登录检测,但这代码行数也不比自己写逻辑的少,而且还要每个控制器去配置这还得了?

    那当然还是封装一个基础控制器,其它控制器继承它来实现继承过滤器规则咯

    但这样增加了继承体系总感觉有点不好是吧,还可以这样,定义一个Trait,里面就是behaviors方法:

    namespace app\lib;
    	
    trait TraitCheckLogin{
    	public function behaviors(){
    		return [
    			'access' => [
    				'class' => 'yii\filters\AccessControl',
    				'rules' => [ //检测规则
    					[ //第1条规则
    						'roles' => ['@'], //角色集合,@表示登录用户
    						'allow' => true, //是否允许访问
    					],
    						
    					[ //第2条规则
    						'actions' => ['login', 'register'], //针对本控制器的哪些方法ID生效,这两个ID就是针对actionLogin和actionRegister两个方法生效
    						'roles' => ['?'], //? 表示未登录用户
    						'allow' => true, //允许未登录用户访问
    					],
    				],
    			],
    		];
    	}
    }
    

    然后在各个控制器里加上use TraitCheckLogin;就可以了(因为大部分程序员少接触trait这个知识点所以这样讲了)


  • 配置登录地址

    像上面这样使用了AccessControl过滤器后,在未登录的情况下访问时不会自动跳到登录页面,这样的用户体验不好

    这里我们其实只要给user组件配置一下loginUrl就能让它自动跳过去了:

    'user' => [
    	'identityClass' => 'app\models\User',
    	'enableAutoLogin' => true,
    		
    	'loginUrl' => '/login.html', //!!!重点!!!
    		
    	//'loginUrl' => ['site/show-login'], //可以用数组,底层会拿去Url::to处理
    	//'loginUrl' => 'http://xxx.com/oauth.html', //甚至是绝对地址
    ],
    

方法2:在app初始化的时候就做登录检测,适合中小型的典型应用

追加到配置文件第一层key(相关知识点:在配置里定义事件):

'on beforeAction' => function($event){
	if(!Yii::$app->user->isGuest){
		//已经登录就随便他访问吧
		return;
	}
	
	$isCommonAccessAction = in_array($event->action->controller->module->requestedRoute, [
		'user/register',
		'user/login',
		'site/error',
		'site/captcha',
	]); //是否不登陆可以访问
	
	if(!$isCommonAccessAction){
		$event->isValid = false;
		Yii::$app->response->redirect(Yii::$app->user->loginUrl);
	}
}