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;
}
好了,就這麼實現了,邏輯可能比較垃圾(勿噴)。