前言:
上一篇我们介绍过了如何使用php+jwt。讲述如何制作一个一站式登录平台。打通各个业务方之间的账号壁垒。那么现在我就来介绍下。从业务方的角度,如何去接入一个登录中心
流程

接入登录中心
首先我介绍下域名:
- 登录中心的url是:tp.login.com:81
- 接入方的域名是:tp.admin.com:81
两个完全不一样的域名,也不存在session共享什么的。那么,现在我要把我的tp.admin.com:81接入到tp.login.com:81的账号体系中去。
一:设计回调地址的路由
由于我这次写的一个demo。就是直接在index模块下login控制器里写了个callback方法。如果在生产环境下的话还是推荐强制路由。这样url看上去美观点。好那么我们回调地址就是tp.admin.com:81/index.php/index/login/callback(这里有个细节,这个回调的地址,是不需要做登录验证的,因为刚回调回来的时候,cookie中还没有密文。所以这个控制器不继承有登录验证的那个控制器)
二:申请应用
好了,既然都是我写的demo。就不存在申请不申请了。不过正规的流程应该是接入方会向登录中心的管理员,申请。告知回调地址。登录中心的管理员在app中添加回调地址,随机字符串作为秘钥,并获得appid。
三:开始开发
首先呢,我们将登录中心的地址,和分配给我们的appid 和app_key存到配置文件中方便使用
配置文件
随后,我们既然是接入别人的登录中心,那就不用自己写登录了。直接写登录验证。
登录验证一般来说都会是写到一个控制器基类的__construct()方法里面
class Base extends Controller
{
public $uid;
public $name;
public function __construct()
{
/**
* 1.判断是否有cookie
* 2.没有cookie,拼接回调地址和appid
* 3.如果有cookie,解密code。验签
* 4.延签失败删除cookie
* 5.验签成功,初始化uid,name
*/
try{
$request=request();
$authCode= cookie('authCode');
if (empty($authCode)) {
//拼接回调地址和appid
$appid=config('sso.appid');
//获取当前请求地址
$callback_url=$request->url(true);
//去配置文件中获取登录中心地址
$login_url=config('sso.login_url');
//拼接跳转地址
$url=$login_url."?appid={$appid}&callback_url=".urlencode($callback_url);
$this->redirect($url);
}else{
//如果有cookie
//解密验签并取得cookie中的uid
$uid=Auth::getUidByJwt($authCode);
$this->uid=$uid;
}
}catch (Exception $e){
$this->error($e->getMessage());
}
}
}
重点看看验签获取uid的方法。其实这个方法是一个基础方法扩展而成的。直接来看代码
/**
* 从jwt中获取某个字段
* @param $token
* @param $key
* @return bool
* @throws Exception
*/
public static function getDataByJwt($token, $key)
{
//将token字符串初始化 token对象
$tokenObj = (new Parser())->parse((string)$token);
//实例化加密对象
$signer = new Sha256();
//使用配置中的秘钥验签
$result = $tokenObj->verify($signer, config('sso.app_key'));
if (!$result) {
//验签失败
//删除cookie,避免无限重定向
cookie('authCode');
throw new Exception('验签失败');
}
//使用检查过期时间的方法判断登录是否过期
if ($tokenObj->isExpired()) {
cookie('authCode');
throw new Exception('登录过期');
}
//获取想要的数据
$data = $tokenObj->getClaim($key);
if ($data) {
return $data;
} else {
return false;
}
}
/**
* 使用基础方法,获取uid
* @param $token
* @return bool
* @throws Exception
*/
public static function getUidByJwt($token)
{
return self::getDataByJwt($token, 'uid');
}
其实jwt的包提供了非常丰富的方法,基本对密文没有太多的处理,验签之类的方法都准备好了。使用成本相当的低
上面介绍了验证登录的构造函数,还有一个地方别忘了。那就是我们最开始申请应用的那个回调地址。那个方法需要负责以下几个动作
- 获取登录中心传递过来的参数
- 验证code签名
- 将code写入cookie
- 从定向到用户最初访问的地址
下面来看代码
class Login extends Controller
{
public function callback($code,$redirect)
{
try{
//验签并取出uid
$uid= Auth::getUidByJwt($code);
//uid存在且回调地址存在
if($uid&&$redirect){
//写入cookie
cookie('authCode',$code);
//重定向到用户最初访问的地址
$this->redirect($redirect);
}else{
//避免重定向
cookie('authCode');
$this->error('登录过期');
}
}catch (Exception $e){
//避免重定向
cookie('authCode');
$this->error('登录过期');
}
}
}
当这一次重定向到用户访问的页面时,又会触发登录验证。这个时候,我们已经写好了cookie。cookie也是合法的。就会成功的取出用户的uid。下次用户访问这个应用的别的方法时,也携带这个cookie就可以正常使用了。更方便的是,我们在登录中心这个域名下还保存了一份cookie,当去访问别的应用时,别人的应用认为你没有登录重定向到登录中心后,就会检测到有cookie值并带上值重定向回别的应用。实现免登录
下面简单展示下效果

检测没有登录,重定向到登录中心

随后输入密码账号,点击登录

然后又经历了两次重定向
一次是重定向到注册的回调地址,带上code
一次是写好cookie之后就重定向到最初访问的地址,我们从浏览器上也观察出回到了我们最初输入的那个地址

并且我在首页输出了用户的id 1 这是通过解密jwt得到的uid
现在我们在刷新一下页面、由于已经有cookie保存了。所以不会再做重定向了。

我们还可以试试把tp.admin.com这个域名下的cookie删除,然后在访问首页。看会发生什么

我们刷新下tp.admin.com 的主页

我们一步一步分析
- 重定向到了登录中心
- 登录中心发现有cookie存在就重定向到回调地址,带上cookie和redirect
- 回调地址,验签通过,初始化uid 并且重定向到最初访问的地址,也就是首页
虽然做了几次重定向,但是对于用户来说是察觉不出来的。他体验到的是不需要登录的方便与快捷
好了今天的介绍接入登录中心就写到这里了。虽然还有些不完善的地方,不过这个机制是非常值得学习和可靠的。如果有不对的地方,望大神指正。感谢!
以上
