Spring Session - 按使用者名稱查詢
假設
本指南假設您已經透過使用內建的 Redis 配置支援將 Spring Session 新增到您的應用中。本指南還假設您已經將 Spring Security 應用到您的應用中。然而,本指南具有通用性,只需少量修改即可應用於任何技術,這將在本指南後面討論。
如果您需要學習如何將 Spring Session 新增到您的專案中,請參閱示例和指南列表 |
關於示例
我們的示例使用此功能來使可能已被洩露的使用者會話失效。考慮以下場景
-
使用者去圖書館並登入應用程式。
-
使用者回家後發現忘記登出了。
-
使用者可以登入並使用位置、建立時間、最後訪問時間等線索結束圖書館的會話。
如果我們能讓使用者從任何認證過的裝置上使圖書館的會話失效,那豈不是很好?本示例展示瞭如何實現這一點。
使用 FindByIndexNameSessionRepository
要按使用者名稱查詢使用者,您首先必須選擇一個實現了FindByIndexNameSessionRepository
的 SessionRepository
。我們的示例應用假設 Redis 支援已經設定好,所以我們可以開始了。
對映使用者名稱
只有在開發者指示 Spring Session 哪個使用者與 Session
關聯時,FindByIndexNameSessionRepository
才能按使用者名稱查詢會話。您可以透過確保名為 FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME
的會話屬性填充了使用者名稱來實現。
一般來說,您可以在使用者認證後立即使用以下程式碼實現:
String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
向會話新增額外資料
將額外資訊(例如 IP 地址、瀏覽器、位置和其他詳細資訊)關聯到會話中可能會很有幫助。這樣做使使用者更容易知道他們正在檢視哪個會話。
要實現這一點,請確定您想使用哪個會話屬性以及您希望提供哪些資訊。然後建立一個 Java bean 作為會話屬性新增。例如,我們的示例應用包括會話的位置和訪問型別,如下所示:
public class SessionDetails implements Serializable {
private String location;
private String accessType;
public String getLocation() {
return this.location;
}
public void setLocation(String location) {
this.location = location;
}
public String getAccessType() {
return this.accessType;
}
public void setAccessType(String accessType) {
this.accessType = accessType;
}
private static final long serialVersionUID = 8850489178248613501L;
}
然後,我們在每個 HTTP 請求中使用 SessionDetailsFilter
將這些資訊注入到會話中,如下例所示:
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
HttpSession session = request.getSession(false);
if (session != null) {
String remoteAddr = getRemoteAddress(request);
String geoLocation = getGeoLocation(remoteAddr);
SessionDetails details = new SessionDetails();
details.setAccessType(request.getHeader("User-Agent"));
details.setLocation(remoteAddr + " " + geoLocation);
session.setAttribute("SESSION_DETAILS", details);
}
}
我們獲取所需的資訊,然後將 SessionDetails
設定為 Session
中的一個屬性。當我們按使用者名稱檢索 Session
時,就可以使用該會話像訪問其他任何會話屬性一樣訪問我們的 SessionDetails
。
您可能想知道為什麼 Spring Session 沒有直接提供 SessionDetails 功能。我們有兩個原因。第一個原因是應用可以非常輕鬆地自己實現這一點。第二個原因是會話中填充的資訊(以及更新該資訊的頻率)高度依賴於具體的應用。 |
查詢特定使用者的會話
現在我們可以查詢特定使用者的所有會話了。以下示例展示瞭如何實現:
@Autowired
FindByIndexNameSessionRepository<? extends Session> sessions;
@RequestMapping("/")
public String index(Principal principal, Model model) {
Collection<? extends Session> usersSessions = this.sessions.findByPrincipalName(principal.getName()).values();
model.addAttribute("sessions", usersSessions);
return "index";
}
在我們的示例中,我們查詢當前登入使用者的所有會話。但是,您可以修改此功能,以便管理員可以使用表單指定要查詢哪個使用者。
findbyusername
示例應用
本節介紹如何使用 findbyusername
示例應用。
執行 findbyusername
示例應用
您可以透過獲取原始碼並呼叫以下命令來執行示例:
$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun
為了使示例正常工作,您必須在 localhost 上安裝 Redis 2.8+ 並使用預設埠 (6379) 執行它。或者,您可以更新 RedisConnectionFactory 指向一個 Redis 伺服器。另一種選擇是使用 Docker 在 localhost 上執行 Redis。有關詳細說明,請參閱Docker Redis 倉庫。 |
現在您應該能夠透過 localhost:8080/ 訪問該應用了。
探索 security 示例應用
現在您可以嘗試使用該應用了。輸入以下資訊登入:
-
使用者名稱 user
-
密碼 password
現在點選登入按鈕。您應該會看到一條訊息,表明您已使用之前輸入的使用者登入。您還應該會看到當前登入使用者的活動會話列表。
您可以透過執行以下操作來模擬我們在關於示例部分討論的流程:
-
開啟一個新的隱身視窗並導航到 localhost:8080/
-
輸入以下資訊登入:
-
使用者名稱 user
-
密碼 password
-
-
結束您的原始會話。
-
重新整理原始視窗,您會看到您已登出。