yangzie的身份认证控制

目录
[隐藏]

1.关于身份认证

身份认证就是说在进入系统之前,我们需要知道访问者是否是一个合法的系统用户;最传统的认证方式就是输入在系统中的登录名和密码进行验证,也可以集成其他第三方的用户系统,比如微博,微信,qq等;

不管哪种方式,首先我们需要知道用户是否认证过了,当认证过后就不需要再次让用户进行登录认证;这通常是通过Session来记录用户的认证与否,然后在所有需要进行认证的页面都检查这个Session,如果满足我们标记的值就说明用户已认证登录,不满足则跳转到登录页面,要求用户进行登录。

那么这里就有一个必须要做的体力活:在每个需要认证的页面都加上认证代码,比如:

<?php

checkLogin();

//other code

?>

在一个架构,结构良好的系统里面,加一句检查代码可能没有什么;但是,从业务功能开发者的角度考虑,我为什么要时时刻刻想着用户是否登录了呢?我的工作重心应该就是业务功能这个点,而不应该在耗费脑细胞去考虑其他“系统”应该考虑的事情,也就是说代码执行到我这里,那么用户应该就是存在的,并且是有权限执行我这块代码的;每个业务功能开发者,都不应该去考虑检查用户是否登录,是否有权限等“系统”应该考虑的事情

2.yangzie身份认证

在说明yangzie的身份认证如何处理之前,我们要回顾一下yangzie的代码组织方式:

  1. 按模块(module)组织业务功能
  2. 按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,他们的规则是

  1. no_auths优先级高于auths
  2. 配置的内容都小写
  3. 默认两者都是空数组:array(),表示不需要认证
  4. 可以用字符串“*”表示该模块下的所有C/A
  5. 可以用数组的形式单独指定某个或者某些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标记用户已登录。有点乱吗?我们来梳理一下

  1. 在自己的__module__.php中配置那些需要身份认证
  2. 注册hook:YZE_HOOK_GET_LOGIN_USER,该hook返回登录用户的标志,返回内容自定义
  3. 注册hook:YZE_HOOK_SET_LOGIN_USER,该hook向yangzie注册用户登录的标志,内容就是YZE_HOOK_GET_LOGIN_USER返回的内容
  4. 上面两个hook让yangzie知道如何获取认证用户信息
  5. 注册hook: YZE_FILTER_YZE_EXCEPTION,所有系统的异常都会进入该hook,该hook传入及返回的数据格式是:

    array(“exception”=>$e, “controller”=>$controller, “response”=>$response);

    其中的response就是yangzie的响应,你可以在里面返回一个yze_redirect来指示yangzie在出现某个异常时重定向到哪里去

对于这些hook的注册,我们已经帮你建立好,开发者只需要实现里面的内容即可,该文件在app/hooks/auth.php中,下面是一个具体的项目案例:

auth

这里涉及到了几个yangzie的其他内容:

  1. hook
  2. 响应(视图系统

我们会在后面继续说明。

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-权限控制