1. 程式人生 > >Springboot 使用Redis+Session實現Session共享 , 實現單點登入

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;
}

 

好了,就這麼實現了,邏輯可能比較垃圾(勿噴)。