介绍
介绍
今天福哥带着大家来把会员中心(就是开放给登录用户的功能集中管理模块)的基础框架搭建一下。所谓的基础框架包括了会员中心的导航菜单,还有每个已知功能页面的视图模型以及功能页面的基本权限控制。
这里面有个问题,就是首页应该是公开的(任何人都可以访问),而会员中心里面的功能则必须有用户登录才能操作,并且有用户登录之后login和register都不应该再可以访问到,一个SystemPageController无法满足三种不同的需求,怎么办?
这里就需要一个权限模块来针对不同的资源路径使用不同的权限机制。福哥建立了一个permission模块,用来处理权限分配的逻辑,包括登录授权功能(login)、登录状态功能(status)、无授权功能(nothing)、非登录授权功能(nologin)四种授权模式。
因为PHP是脚本语言,如果一个PHP程序里的代码太多的话会影响整体性能,所以我们在设计程序的时候尽量将不同模块用到的功能分开来写,避免代码集中到一起的问题。福哥将登录状态的功能从user模块分离到了login模块里面了,这样在大多数情况下需要获取登录状态,但不需要做其他操作,提高TFUMS系统的性能。
模型login
createToken
public function createToken(int $userID, bool $remember=false):string {
$tfredis = $this->tfphp->getDatabase()->getRedis();
$token = md5(microtime());
$tokenKey = "token_". $token;
if($tfredis->set($tokenKey, $userID)
&& $tfredis->expire($tokenKey, ($remember) ? 60*60*24*7 : 60*60*8)){
return $token;
}
return null;
}getIDByToken
public function getIDByToken(string $token):int {
$tfredis = $this->tfphp->getDatabase()->getRedis();
$tokenKey = "token_". $token;
return intval($tfredis->get($tokenKey));
}clearToken
public function clearToken(string $token):bool {
$tfredis = $this->tfphp->getDatabase()->getRedis();
$tokenKey = "token_". $token;
return $tfredis->delete($tokenKey);
}detectLoginStatus
public function detectLoginStatus(){
$login = new login($this->tfphp);
$cookie = $this->tfphp->getRequest()->cookie;
$id = $cookie->get("tfums_id");
$token = $cookie->get("tfums_token");
try{
$idInToken = $login->getIDByToken($token);
if($id == $idInToken){
$this->loginStatus = new loginStatus();
$this->fillEntityByTable($this->loginStatus, "user", array($id));
if($this->loginStatus->userID > 0){
return true;
}
}
}
catch(\TypeError $e){ }
return false;
}getLoginStatus
public function getLoginStatus():?loginStatus {
return $this->loginStatus;
}模型permission
detect
private function detect(){
$this->login->detectLoginStatus();
}match
private function match($pattern):bool {
if(preg_match("/". $pattern. "/", $this->requestUri)){
return true;
}
return false;
}login
private function login(){
$this->detect();
$loginStatus = $this->login->getLoginStatus();
if(!($loginStatus != null && $loginStatus->userID > 0)){
$this->tfphp->getResponse()->location($this->tfphp->getRequest()->server->BASE_URI. "login.htm");
}
}nologin
private function nologin(){
$this->detect();
$loginStatus = $this->login->getLoginStatus();var_dump($this->requestUri);
if($loginStatus != null && $loginStatus->userID > 0){
$this->tfphp->getResponse()->location($this->tfphp->getRequest()->server->BASE_URI. "member/");
}
}status
private function status(){
$this->detect();
}nothing
private function nothing(){
}process
protected function process(){
if($this->match("\/member\/")){
$this->login();
}
else if($this->match("(login|register)\.htm")){
$this->nologin();
}
else{
$this->nothing();
}
}getLoginStatus
public function getLoginStatus():?loginStatus {
return $this->login->getLoginStatus();
}讲解
模型login
createToken
创建用户登录状态的token
getIDByToken
通过用户登录状态的token获取登录用户ID
clearToken
清除用户登录状态的token(注销操作)
detectLoginStatus
探测用户登录状态,使用loginStatus实体来保存用户登录状态信息
getLoginStatus
获取loginStatus实体对象
模型permission
detect
调用login::detectLoginStatus方法探测用户登录状态
match
使用正则表达式检查当前资源路径是否符合匹配规则
login
登录授权模式,如果当前没有用户登录则跳转至登录页面
nologin
非登录授权模式,如果当前有用户登录则跳转至会员中心首页
status
只探测登录状态,不做处理
nothing
不探测登录状态
process
重载基类的process方法,将user_process留给业务控制器对象重载
getLoginStatus
获取loginStatus实体对象
使用
在SystemAPIController和SystemPageController两个中间层控制器的process方法里面调用permission对象,实现权限控制。

总结
今天福哥带着童鞋们解决了TFUMS系统的授权模式问题。这个授权模式在不同的系统里面,有着不同的设计思路,在不同的工程师手里也有着各种各样的解决方案,福哥只是把其中一种介绍给了大家。
下一课,福哥将带着大家完成修改个人资料功能,敬请期待~~