redis的详解和项目应用之SESSION共享

前言:承接上文 redis的详解和项目应用之PHP操作总结

三、项目应用 

3.1 项目介绍

此项目为了实现单点登录(Single Sign On),简称为 SSO,是比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

单点登录使用的是session共享技术,然而session是不能跨服务器的,但是将session存储在一台 redis/memcache 缓存服务器上就可以实现跨服务器session信息共享,实现过程如下图所示:

过程说明:

需要准备一台web服务器用来做一个授权登录系统,然后再准备几台其他站点的web服务器。实现是通过登录后的session信息存储到redis中,并且通过跳转将SESSIONID传递到相关的各个系统站点的cookie中来记录登录状态,通过cookie中的SESSIONID请求登录服务器来获取存储到redis中的用户信息,即实现单点登录。

3.2 前期配置

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"

3.3 实现结果

代码:

登录服务器的 config.php 文件

<?php

/**
* 配置文件,安装个人项目的配置来
*/

//同步登录web域名数组
$synUrlAll = [ 
	web1, 
	web2,
];

//认证中心的web域名
$centerUrl = centerUrl;

//私钥
$privateKey = 'redisKey';

//redis配置
$redisConfig = [
	'host' => centerUrl,
	'port' => '6379',
	'timeout' => '604800',
	'auth_pass' => YOURPASSPHRASE,
];

登录服务器的 center.php 文件

<?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 文件(统一登录页面)

<!DOCTYPE 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 文件

<?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();
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_68949064

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值