1.关于身份认证
身份认证就是说在进入系统之前,我们需要知道访问者是否是一个合法的系统用户;最传统的认证方式就是输入在系统中的登录名和密码进行验证,也可以集成其他第三方的用户系统,比如微博,微信,qq等;
不管哪种方式,首先我们需要知道用户是否认证过了,当认证过后就不需要再次让用户进行登录认证;这通常是通过Session来记录用户的认证与否,然后在所有需要进行认证的页面都检查这个Session,如果满足我们标记的值就说明用户已认证登录,不满足则跳转到登录页面,要求用户进行登录。
那么这里就有一个必须要做的体力活:在每个需要认证的页面都加上认证代码,比如:
<?php
checkLogin();
//other code
?>
在一个架构,结构良好的系统里面,加一句检查代码可能没有什么;但是,从业务功能开发者的角度考虑,我为什么要时时刻刻想着用户是否登录了呢?我的工作重心应该就是业务功能这个点,而不应该在耗费脑细胞去考虑其他“系统”应该考虑的事情,也就是说代码执行到我这里,那么用户应该就是存在的,并且是有权限执行我这块代码的;每个业务功能开发者,都不应该去考虑检查用户是否登录,是否有权限等“系统”应该考虑的事情
2.yangzie身份认证
在说明yangzie的身份认证如何处理之前,我们要回顾一下yangzie的代码组织方式:
- 按模块(module)组织业务功能
- 按MVC结构组织功能代码
也就是每个“点”,都对应到了一个具体的M/C/A(module/controller/action);并且他们组织在具体的module里面;那么接下来开发者需要做的就是配置一下,指定那些M/C/A需要身份认证,这是在__module__.php进行的:
class Front_Module extends YZE_Base_Module {
public $auths = array (
"*"
);
public $no_auths = array (
"signin" => "*"
);
protected function _config () { }
}
上面就是一个例子,其中$auths配置的就是该module下需要身份认证的C/A,$no_auths配置的就是该模块下不需要认证的C/A,他们的规则是
- no_auths优先级高于auths
- 配置的内容都小写
- 默认两者都是空数组:array(),表示不需要认证
- 可以用字符串“*”表示该模块下的所有C/A
- 可以用数组的形式单独指定某个或者某些C/A,数组每一项代表一个C/A,其中C必须是控制器短名(比如index_controller,短名就是index),A可以是具体的某个action名字,也可以是*或者合法的正则表达式,比如”index”=>”foo|bar”,
上面的例子含义是:front模块下所有的C/A都需要身份认证,但排除index控制器下的所有Action和Signin下的所有Action
开发者根据yangzie约定的代码组织方式,规划好代码后,只需要在__module__.php配置一下即可,无需再自己的controller业务代码中总是要记得加入用户是否登录的判断代码。
3.__module__.php配置好就会进行身份认证了吗?
__module__.php配置只是第一步:说明那些地方需要身份认证,但具体认证是如何做的呢(比如打开登录界面让用户登录)?
这需要通过yangzie的hook来实现,yangzie并不知道一个系统是如何标志用户是否认证登录的,认证的标志是存Session还是DB,怎么存的,yangzie并不知道;他只知道根据配置某个M/C/A需要身份认证,这是他会触发一个hook:YZE_HOOK_GET_LOGIN_USER
开发者需要实现并注册这个hook,返回自己的系统如何标志用户是否登录的信息,比如返回登录用户的id或者用户信息;
如果开发者没有实现该hook,yangzie将抛出一个异常(还记得yangzie的基本原则吗?):YZE_Need_Signin_Exception
开发者需要注册一个hook:YZE_FILTER_YZE_EXCEPTION,来监听系统抛出的异常,如果是YZE_Need_Signin_Exception则返回登录地址的重定向信息:
YZE_Hook::add_hook(YZE_FILTER_YZE_EXCEPTION, function ($datas){
//如果array("exception"=>$e, "controller"=>$controller, "response"=>$response)
// 把signin替换成自己的登录url
$request = YZE_Request::get_instance();
if(! is_a($datas['exception'], "\\yangzie\\YZE_Need_Signin_Exception")) return $datas;
$datas['response'] = new YZE_Redirect("/signin", $datas['controller']);
if($request->isInWeixin()){
$datas['response'] = new YZE_Redirect("/wx/signin", $datas['controller']);
}
return $datas;
});
在自己的登录逻辑成功后,通过hook:YZE_HOOK_SET_LOGIN_USER,来想yangzie标记用户已登录。有点乱吗?我们来梳理一下
- 在自己的__module__.php中配置那些需要身份认证
- 注册hook:YZE_HOOK_GET_LOGIN_USER,该hook返回登录用户的标志,返回内容自定义
- 注册hook:YZE_HOOK_SET_LOGIN_USER,该hook向yangzie注册用户登录的标志,内容就是YZE_HOOK_GET_LOGIN_USER返回的内容
- 上面两个hook让yangzie知道如何获取认证用户信息
- 注册hook: YZE_FILTER_YZE_EXCEPTION,所有系统的异常都会进入该hook,该hook传入及返回的数据格式是:
array(“exception”=>$e, “controller”=>$controller, “response”=>$response);
其中的response就是yangzie的响应,你可以在里面返回一个yze_redirect来指示yangzie在出现某个异常时重定向到哪里去
对于这些hook的注册,我们已经帮你建立好,开发者只需要实现里面的内容即可,该文件在app/hooks/auth.php中,下面是一个具体的项目案例:
这里涉及到了几个yangzie的其他内容:
我们会在后面继续说明。
4.接下来
至此,yangzie的身份认证就完成了,他把传统的加检测代码的方式,通过hook独立出来,统一实现;需要验证的地方只需要在__module__.php说一声,“我需要认证”便可。
那么如何得到认证的用户信息呢?还记得注册的hook:YZE_HOOK_GET_LOGIN_USER,YZE_HOOK_SET_LOGIN_USER,你已经告诉yangzie我怎么标记登录用户了,那你自然知道如何获得登录用户信息,比如上面例子中的$_SESSION[‘admin’]就是登录用户;但我们建议的方式是直接调用hook获取:
YZE_HOOK:do_hook(YZE_HOOK_GET_LOGIN_USER)
身份认证完成了,那下面就是要验证这个用户身份的权限了,他能访问什么,不能访问什么?请继续阅读《ACL-权限控制》