Springboot 使用Redis+Session实现Session共享 , 实现单点登录

话说在前:

  在你打开我的这篇东西的时候,你应该学会了基于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;
}

好了,就这么实现了,逻辑可能比较垃圾(勿喷)。

猜你喜欢

转载自blog.csdn.net/qq_35387940/article/details/84388644