话说在前:
在你打开我的这篇东西的时候,你应该学会了基于springboot项目使用Redis了,因为我不会在这篇过多去介绍·从redis基本配置。
然后, 你如果登录这模块,使用了shiro 或者说是 security ,没关系的。 我也是结合shiro一起使用的。 我主要分享一个思路,鄙人的实现逻辑。 不一定是最好,但是你可以这么干。
不废话,进入正题了,
实现session共享比较少东西,那么我就先讲这个咯。
首先,导包。
在pom.xml文件里面加入以下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
jar包不做多解释了,看那个artifactId的内容应该能知道干啥的。
然后是yml文件:
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password:
jedis.pool.max-idle: 100
jedis.pool.max-wait: -1ms
jedis.pool.min-idle: 2
timeout: 2000ms
是的,很精简。
然后是,到你的RedisConfig文件上面,开启redis的session关联注解
@EnableRedisHttpSession
如:
OK,我们开始共享session咯!
在controller文件里面写2个方法吧,
@GetMapping("/setSessionId")
public String setredisResult(HttpServletRequest request){
HttpSession session = request.getSession();
session.setAttribute("sessionId17789008","17789008");
return "set成功,已经存入session域且redis里面也有了...";
}
@GetMapping("/getSessionId")
public String redisResult(HttpServletRequest request) {
HttpSession session = request.getSession();
String sessid = (String) session.getAttribute("sessionId17789008");
return "sessionId:"+sessid;
}
先运行第一个, 如下:
然后再瞟一眼redis数据库,
是的,没错,开启了注解之后,我们只要往session域里面存储信息,redis也会来参一脚。可以看到redis也存储了这个session信息。
怎么验证共享呢? 直接运行第二个方法? 不是的。
刚才我们在8033端口运行的第一个方法, 接下来, 我们要去开另一个项目,然后配置不同的端口,例如是8043啊之类的,
然后根据sessionID去获取刚才的值。
然后你就发现也能拿到。 这就是模拟的不同服务之间达到session共享(我就不去贴图了这里)。
然后到了单点登录思路!!!! 是的 这是我这篇东西主要想分享的。
单点登录: 就是你目前这个电脑(设备),只能登录一个账号,就像我们的CSDN论坛一样, 登录一个账号。 然后再去打开CSDN,默认就是当前账号登录。 如果你想登录另一个账号, 不好意思。除非你点退出或者等一段时间(设置的,无论是session管理角度或者设置数据时间都行),否则无法登录。
进入正题,
先贴一段文字逻辑:
//假设一个用户登录进来, 先将他的“ip地址”作为key, “账户名”作为value 。 验证账号和密码都对了,就存储redis。
//然后下一次,又想登录的时候, 就算他输入的是别的账号和密码,点击登录。 我们先不处理, 先把他的IP地址获取出来,
//然后根据IP地址作为key去redis去查, 如果查出的信息不为空, 证明登录过。 那么直接传入将查出的账号名的账号实现登录(可以先拿出账号名,去数据库查他的密码,然后调一个登录验证接口,让他登录)
// 如果这个IP地址的用户想换账号登录,那么必须在上一个账号页面点注销。 那么将会根据这个注销操作去redis删除关联IP地址的数据。
//这样再登录,通过账号密码校验,就会存储新的与IP地址关联的账号数据进入redis。
可以慢慢读读上面的逻辑,基本实现就是这样。
然后我们陪同思路整一下(其余自己去连贯哈,因为我写好久了,现在代码有很多其他业务,不想重新写了,提供最重要的环节解析。)
首先,
一个账号登录, 我们不管他填的什么账号还是密码, 我们先把的IP地址整下来。
先贴一个扒ip地址的工具类,
package com.siit.vehicleApi.vehicleServiceInterface.util;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @Author : JCccc
* @CreateTime : 2018-11-23
* @Description :
* @Point: Keep a good mood
**/
public class IpUtil {
public static String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress="";
}
// ipAddress = this.getRequest().getRemoteAddr();
return ipAddress;
}
}
然后是后面单点登录处理的逻辑伪代码里面,如下步骤:
@RequestMapping(value = "/testMapping", method = RequestMethod.GET)
public String testMapping(HttpServletRequest request) {
//获取IP地址
String ipAddress =IpUtil.getIpAddr(request);
System.out.println(ipAddress);
//模拟从前端拿到的账号名
String accountName="testSign0001";
//根据自己的编码规则拼接存储的key或者是查询的key
String CheckKey=ipAddress+accountName;
if(stringRedisTemplate.boundValueOps(CheckKey).get()!=null){
//不为空,那就是登录过了,redis里面有数据
//1.直接根据这个key,把value拿出来! 我们存在redis里面 是 key : value(账号名)
//2.根据账号名 ,去Mysql(或者其他)把对应账号密码整出来
//3.正常调用你的登录方法(我是shiro框架验证)
//4.实现单点登录 return "xxx.html"
}
else{
//那就是空,证明这个家伙没登路过 , 或者说正常注销啊等等
//1.没登录过嘛,那就正常调用你的登录方法(我是shiro框架验证)
//2.校验登录,不成功,回去登录页面咯;成功,接下来
//3.那我们把key ,value存进redis里面去, 用于下次单点登录校验 (设置了一小时数据自己消失,也就是单点登录的时间设置,可以自己设置)
// stringRedisTemplate.opsForValue().set(CheckKey, accountName, 3600, TimeUnit.SECONDS);
//4.正常登录完成,进去首页啥的, return "xxx.html"
}
}
然后再是,用户点击页面上的退出登录(注销)的时候, 我们让他退出前调用一下删除redis单点登录校验的数据(当然时间够了,数据也是自己消失),这样就不影响他下次登其他账户了:
@RequestMapping(value = "/deleteRedisInfo", method = RequestMethod.GET)
public boolean deleteRedisInfo(HttpServletRequest request){
共享
//获取IP地址
String ipAddress=IpUtil.getIpAddr(request);
//获取当前账户的用户名 (你可以通过之前的值去seesion拿或者怎么样都行)
String accountName="testSign0001";
try {
stringRedisTemplate.delete(ipAddress+accountName);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
好了,就这么实现了,逻辑可能比较垃圾(勿喷)。