Spring Session - 依使用者名稱尋找

本指南說明如何使用 Spring Session 依使用者名稱尋找工作階段。

您可以在 findbyusername 應用程式中找到已完成的指南。

假設

本指南假設您已透過使用內建的 Redis 組態支援將 Spring Session 新增至您的應用程式。本指南也假設您已將 Spring Security 應用於您的應用程式。然而,本指南在某種程度上是通用的,並且可以應用於任何技術,只需進行最少的變更,我們將在本指南稍後討論。

如果您需要學習如何將 Spring Session 新增至您的專案,請參閱範例和指南列表

關於範例

我們的範例使用此功能來使可能已遭洩露的使用者工作階段失效。請考慮以下情境

  • 使用者前往圖書館並驗證應用程式。

  • 使用者回到家並意識到他們忘記登出。

  • 使用者可以使用位置、建立時間、上次存取時間等線索從圖書館登入並結束工作階段。

如果我們可以讓使用者從他們驗證的任何裝置使圖書館的工作階段失效,那不是很好嗎?此範例示範了這如何成為可能。

使用 FindByIndexNameSessionRepository

若要依使用者名稱查詢使用者,您必須先選擇實作 FindByIndexNameSessionRepositorySessionRepository。我們的範例應用程式假設 Redis 支援已設定完成,因此我們已準備就緒。

對應使用者名稱

只有在開發人員指示 Spring Session 將哪個使用者與 Session 關聯時,FindByIndexNameSessionRepository 才能依使用者名稱尋找工作階段。您可以透過確保名稱為 FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME 的工作階段屬性已填入使用者名稱來執行此操作。

一般來說,您可以在使用者驗證後立即使用以下程式碼來執行此操作

String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);

使用 Spring Security 對應使用者名稱

由於我們使用 Spring Security,因此使用者名稱會自動為我們建立索引。這表示我們無需執行任何步驟來確保使用者名稱已建立索引。

將其他資料新增至工作階段

將其他資訊 (例如 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;

}

然後,我們使用 SessionDetailsFilter 將該資訊注入到每個 HTTP 請求的工作階段中,如下列範例所示

@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/ 存取應用程式

探索安全性範例應用程式

您現在可以嘗試使用該應用程式。輸入以下內容以登入

  • 使用者名稱 user

  • 密碼 password

現在按一下登入按鈕。您現在應該會看到一則訊息,指出您已使用先前輸入的使用者登入。您也應該會看到目前已登入使用者的作用中工作階段清單。

您可以透過執行以下操作來模擬我們在關於範例章節中討論的流程

  • 開啟新的無痕視窗並導覽至 localhost:8080/

  • 輸入以下內容以登入

    • 使用者名稱 user

    • 密碼 password

  • 結束您的原始工作階段。

  • 重新整理原始視窗並查看您已登出。