前言:承接上文 redis的详解和项目应用之PHP操作总结
此项目为了实现单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
单点登录使用的是session共享技术,然而session是不能跨服务器的,但是将session存储在一台 redis/memcache 缓存服务器上就可以实现跨服务器session信息共享,实现过程如下图所示:
过程说明:
需要准备一台web服务器用来做一个授权登录系统,然后再准备几台其他站点的web服务器。实现是通过登录后的session信息存储到redis中,并且通过跳转将SESSIONID传递到相关的各个系统站点的cookie中来记录登录状态,通过cookie中的SESSIONID请求登录服务器来获取存储到redis中的用户信息,即实现单点登录。
1、准备一台登录服务器,安装 redis-server,在ubuntu服务器执行
apt install redis-server
安装需要配置远程连接,建议可看我之前发布的文章 redis的详解和项目应用之数据类型_m0_68949064的博客-CSDN博客
2、 将登录服务器和其他web服务器上的PHP都安装上 php-redis 扩展,在ubuntu服务器上执行
- # 依照个人的php版本进行安装redis扩展
- apt install php7.2-redis
3、修改php.ini来配置将session存储到远程redis中
- # 修改php.ini文件中 [Session] 下的配置
- session.save_handler = redis
- session.save_path = "tcp://ip:6379?auth=YOURPASSPHRASE"
代码:
登录服务器的 config.php 文件
-
- /**
- * 配置文件,安装个人项目的配置来
- */
-
- //同步登录web域名数组
- $synUrlAll = [
- web1,
- web2,
- ];
-
- //认证中心的web域名
- $centerUrl = centerUrl;
-
- //私钥
- $privateKey = 'redisKey';
-
- //redis配置
- $redisConfig = [
- 'host' => centerUrl,
- 'port' => '6379',
- 'timeout' => '604800',
- 'auth_pass' => YOURPASSPHRASE,
- ];
登录服务器的 center.php 文件
- header('Content-Type:application/json; charset=utf-8');
- error_reporting(E_ERROR | E_CORE_ERROR | E_PARSE);
-
- include_once "./config.php";
- /**
- * 登录认账中心
- */
- class center
- {
- protected $synUrlAll;
- protected $centerUrl;
- protected $privateKey;
- protected $redisConfig;
-
- function __construct($synUrlAll, $centerUrl, $privateKey, $redisConfig)
- {
- $this->synUrlAll = $synUrlAll;
- $this->centerUrl = $centerUrl;
- $this->privateKey = $privateKey;
- $this->redisConfig = $redisConfig;
- }
-
- public function toLogin()
- {
- $data = $_POST;
- if(!isset($data['username']) || !$data['username']){
-
- return $this->returnJosn(500, '缺少username参数');
- }
-
- if(!isset($data['passwd']) || !$data['passwd']){
-
- return $this->returnJosn(500, '缺少passwd参数');
- }
-
- // 此处登录验证省略,并假设用户ID为1
-
- $userInfo = [
- 'uid' => 1,
- 'username' => $data['username'],
- 'passwd' => $data['passwd'],
- ];
-
- $login_key = 'PHPREDIS_SESSION:'.session_id();
-
- $_SESSION['uid'] = 1;
- $_SESSION['userInfo'] = $userInfo;
-
- setcookie('login_key', $login_key, time()+3600*24, '/');
- return $this->synAllWeb($login_key);
-
- //return $this->returnJosn(200, '登录成功');
-
- }
-
- //同步登录
- public function synLogin()
- {
- $data = $_GET;
- if(!isset($data['login_key']) || !$data['login_key']){
-
- return $this->returnJosn(500, '缺少login_key参数');
- }
-
- $login_key = base64_decode($data['login_key']);
- $login_key = substr($login_key, 0, strlen($login_key)-strlen($this->privateKey));
-
- setcookie('login_key', $login_key, time()+3600*24, '/');
-
- header("Location:".base64_decode($data['returnUrl']).$data['urlAll']);
- exit;
- }
-
- //将登录的sessionid同步至其他网站
- public function synAllWeb($login_key = '')
- {
- if(!$login_key){
- $login_key = $_COOKIE['login_key'];
- }
-
- if(isset($_GET['urlAll'])){
- $urlAll = isset($_GET['urlAll']) ? trim(base64_decode($_GET['urlAll'])) : '';
- $urlAll = json_decode($urlAll, true);
- }else{
- $urlAll = $this->synUrlAll;
- }
-
- if(is_array($urlAll) && !empty($urlAll)){
- sort($urlAll);
- $url = $urlAll[0];
- unset($urlAll[0]);
- header("Location:http://".$url."/web.php?act=synLogin&login_key=".base64_encode($login_key.$this->privateKey)."&urlAll=".base64_encode(json_encode($urlAll))."&returnUrl=".base64_encode("http://".$this->centerUrl."/redisObj/center.php?act=synAllWeb&urlAll="));
- exit;
- }else{
- return $this->isLogin();
- }
-
- }
-
- public function isLogin()
- {
- if(isset($_COOKIE['login_key']) && $_COOKIE['login_key']){
- $redis = $this->redis();
- $session_str = stripslashes($redis->get($_COOKIE['login_key']));
- if($session_str){
- $index = strpos($session_str, ';');
- $str = substr($session_str, ($index+1));
- $userInfo = unserialize(str_replace('userInfo|', '', $str));
- return $this->returnJosn(200, '登录中', json_encode(['userInfo'=>$userInfo]));
- }else{
- unset($_COOKIE['login_key']);
- return $this->returnJosn(500, '登录失效');
- }
- }else{
- return $this->returnJosn(500, '登录失效');
- }
- }
-
- public function loginOut()
- {
- unset($_COOKIE['login_key']);
- unset($_SESSION['uid']);
- unset($_SESSION['userInfo']);
-
- session_destroy();
- return $this->returnJosn(200, '已退出登录');
- }
-
- protected function redis()
- {
- $redisConfig = $this->redisConfig;
- $redis = new Redis();
- $redis->pconnect($redisConfig['host'], $redisConfig['port'], $redisConfig['timeout']);
- $redis->auth($redisConfig['auth_pass']);
- return $redis;
- }
-
- protected function returnJosn($code, $msg = '', $data = array())
- {
- echo json_encode([$code, $msg, $data], JSON_UNESCAPED_UNICODE);
- exit;
- }
- }
-
- session_start();
- $act = isset($_GET['act']) ? trim($_GET['act']) : 'isLogin';
-
- if($act){
- $center = new center($synUrlAll, $centerUrl, $privateKey, $redisConfig);
- $center->$act();
- }
登录服务器的 login.html 文件(统一登录页面)
- html>
- <html>
- <head>
- <title>登录页面title>
- head>
- <body>
- <meta charset="utf-8">
- <h3>登录页面h3>
- <form action="./center.php?act=toLogin" method="post">
- <input type="text" name="username" value="username11"><br/>
- <input type="password" name="passwd" value="pwd11"><br/>
- <input type="submit" value="登录">
- form>
- body>
- html>
其他web服务器的 web.php 文件
- header('Content-Type:application/json; charset=utf-8');
- error_reporting(E_ERROR | E_CORE_ERROR | E_PARSE);
-
- /**
- * 站点1,使用此方法登录依次其他站点
- */
- class web1
- {
- protected $privateKey;
- protected $redisConfig;
-
- function __construct($privateKey, $redisConfig)
- {
- $this->privateKey = $privateKey;
- $this->redisConfig = $redisConfig;
- }
-
- //同步登录
- public function synLogin()
- {
- $data = $_GET;
- if(!isset($data['login_key']) || !$data['login_key']){
-
- return $this->returnJosn(500, '缺少login_key参数');
- }
-
- $login_key = base64_decode($data['login_key']);
- $login_key = substr($login_key, 0, strlen($login_key)-strlen($this->privateKey));
-
- setcookie('login_key', $login_key, time()+3600*24, '/');
-
- header("Location:".base64_decode($data['returnUrl']).$data['urlAll']);
- exit;
- }
-
-
- public function isLogin()
- {
- if(isset($_COOKIE['login_key']) && $_COOKIE['login_key']){
- $redis = $this->redis();
- $session_str = stripslashes($redis->get($_COOKIE['login_key']));
- if($session_str){
- $index = strpos($session_str, ';');
- $str = substr($session_str, ($index+1));
- $userInfo = unserialize(str_replace('userInfo|', '', $str));
- return $this->returnJosn(200, '登录中', json_encode(['userInfo'=>$userInfo]));
- }else{
- unset($_COOKIE['login_key']);
- return $this->returnJosn(500, '登录失效');
- }
- }else{
- return $this->returnJosn(500, '登录失效');
- }
- }
-
- public function loginOut()
- {
- unset($_COOKIE['login_key']);
- return $this->returnJosn(200, '已退出登录');
- }
-
- protected function redis()
- {
- $redisConfig = $this->redisConfig;
- $redis = new Redis();
- $redis->pconnect($redisConfig['host'], $redisConfig['port'], $redisConfig['timeout']);
- $redis->auth($redisConfig['auth_pass']);
- return $redis;
- }
-
- protected function returnJosn($code, $msg = '', $data = array())
- {
- echo json_encode([$code, $msg, $data], JSON_UNESCAPED_UNICODE);
- exit;
- }
- }
-
- $act = isset($_GET['act']) ? trim($_GET['act']) : 'isLogin';
-
- //私钥
- $privateKey = 'redisKey';
-
- //redis配置
- $redisConfig = [
- 'host' => '106.12.155.232',
- 'port' => '6379',
- 'timeout' => '604800',
- 'auth_pass' => 'redispwd11',
- ];
-
- if($act){
- $web1 = new web1($privateKey, $redisConfig);
- $web1->$act();
- }