JSP 標籤庫

宣告標籤庫

要使用任何標籤,您必須在 JSP 中宣告安全標籤庫

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

authorize 標籤

此標籤用於確定其內容是否應該被評估。在 Spring Security 3.0 中,它有兩種使用方式。

Spring Security 2.0 中的傳統選項也受支援,但不建議使用。

第一種方法使用 web 安全表示式,該表示式在標籤的 access 屬性中指定。表示式評估委託給應用程式上下文中定義的 SecurityExpressionHandler<FilterInvocation>(您應該在 <http> 名稱空間配置中啟用 web 表示式以確保此服務可用)。例如,您可能有

<sec:authorize access="hasRole('supervisor')">

This content will only be visible to users who have the "supervisor" authority in their list of <tt>GrantedAuthority</tt>s.

</sec:authorize>

當與 Spring Security 的 PermissionEvaluator 結合使用時,此標籤也可以用於檢查許可權

<sec:authorize access="hasPermission(#domain,'read') or hasPermission(#domain,'write')">

This content will only be visible to users who have read or write permission to the Object found as a request attribute named "domain".

</sec:authorize>

一個常見的需求是隻顯示特定的連結,前提是使用者確實被允許點選它。我們如何預先確定是否允許某些操作?此標籤還可以以另一種模式執行,讓您將特定的 URL 定義為一個屬性。如果使用者被允許呼叫該 URL,則評估標籤體。否則,將跳過。因此,您可能會看到類似以下內容

<sec:authorize url="/admin">

This content will only be visible to users who are authorized to send requests to the "/admin" URL.

</sec:authorize>

要使用此標籤,您還必須在應用程式上下文中有一個 WebInvocationPrivilegeEvaluator 例項。如果您使用名稱空間配置,將自動註冊一個。這是一個 DefaultWebInvocationPrivilegeEvaluator 例項,它為提供的 URL 建立一個模擬 Web 請求,並呼叫安全攔截器以檢視請求是成功還是失敗。這讓您可以委託給透過在 <http> 名稱空間配置中使用 intercept-url 宣告定義的訪問控制設定,從而避免在 JSP 中重複資訊(例如所需的角色)。您還可以將此方法與 method 屬性(提供 HTTP 方法,如 POST)結合使用,以進行更具體的匹配。

您可以透過設定 var 屬性為變數名,將評估標籤(無論是否授予或拒絕訪問)的布林結果儲存在頁面上下文範圍的變數中,從而避免在頁面其他地方重複和重新評估條件。

停用標籤授權以進行測試

在頁面中為未經授權的使用者隱藏連結並不能阻止他們訪問 URL。例如,他們可以直接在瀏覽器中輸入 URL。作為測試過程的一部分,您可能希望顯示隱藏區域,以檢查連結在後端是否確實是安全的。如果您將 spring.security.disableUISecurity 系統屬性設定為 trueauthorize 標籤仍然會執行,但不會隱藏其內容。預設情況下,它還會用 <span class="securityHiddenUI">…​</span> 標籤環繞內容。這使您可以使用特定的 CSS 樣式(例如不同的背景顏色)來顯示“隱藏”內容。例如,嘗試在啟用此屬性的情況下執行“tutorial”示例應用程式。

如果您想更改環繞文字(預設是 span 標籤),您還可以設定 spring.security.securedUIPrefixspring.security.securedUISuffix 屬性(或者使用空字串完全移除它)。

authentication 標籤

此標籤允許訪問儲存在安全上下文中的當前 Authentication 物件。它直接在 JSP 中渲染該物件的屬性。例如,如果 Authentication 物件的 principal 屬性是 Spring Security 的 UserDetails 物件的一個例項,則使用 <sec:authentication property="principal.username" /> 會渲染當前使用者的名稱。

當然,對於此類事情,不一定非要使用 JSP 標籤,有些人更喜歡在檢視中保留儘可能少的邏輯。您可以在 MVC 控制器中訪問 Authentication 物件(透過呼叫 SecurityContextHolder.getContext().getAuthentication()),並將資料直接新增到模型中,供檢視渲染。

accesscontrollist 標籤

此標籤僅在與 Spring Security 的 ACL 模組一起使用時有效。它檢查指定域物件的所需許可權的逗號分隔列表。如果當前使用者具有所有這些許可權,則評估標籤體。如果他們沒有,則跳過。

通常,此標籤應被視為已棄用。請改為使用 authorize 標籤

以下清單顯示了一個示例

<sec:accesscontrollist hasPermission="1,2" domainObject="${someObject}">

<!-- This will be shown if the user has all of the permissions represented by the values "1" or "2" on the given object. -->

</sec:accesscontrollist>

許可權被傳遞到應用程式上下文中定義的 PermissionFactory,將其轉換為 ACL Permission 例項,因此它們可以是工廠支援的任何格式。它們不必是整數。它們可以是字串,例如 READWRITE。如果未找到 PermissionFactory,則使用 DefaultPermissionFactory 的例項。應用程式上下文中的 AclService 用於載入所提供物件的 Acl 例項。Acl 會被呼叫所需的許可權來檢查是否所有許可權都已授予。

此標籤也支援 var 屬性,其方式與 authorize 標籤相同。

csrfInput 標籤

如果啟用了 CSRF 保護,此標籤會插入一個隱藏表單欄位,其名稱和值與 CSRF 保護令牌匹配。如果未啟用 CSRF 保護,此標籤不輸出任何內容。

通常,Spring Security 會自動為您使用的任何 <form:form> 標籤插入 CSRF 表單欄位,但如果由於某種原因無法使用 <form:form>csrfInput 是一個方便的替代品。

您應該將此標籤放置在 HTML <form></form> 塊內,通常放置其他輸入欄位的位置。請勿將此標籤放置在 Spring <form:form></form:form> 塊內。Spring Security 會自動處理 Spring 表單。以下清單顯示了一個示例

	<form method="post" action="/do/something">
		<sec:csrfInput />
		Name:<br />
		<input type="text" name="name" />
		...
	</form>

csrfMetaTags 標籤

如果啟用了 CSRF 保護,此標籤會插入包含 CSRF 保護令牌的表單欄位名、請求頭名和 CSRF 保護令牌值的 meta 標籤。這些 meta 標籤對於在應用程式中的 JavaScript 中應用 CSRF 保護非常有用。

您應該將 csrfMetaTags 放置在 HTML <head></head> 塊內,通常放置其他 meta 標籤的位置。使用此標籤後,您可以使用 JavaScript 訪問表單欄位名、請求頭名和令牌值。本示例使用 JQuery 使此任務更容易。以下清單顯示了一個示例

<!DOCTYPE html>
<html>
	<head>
		<title>CSRF Protected JavaScript Page</title>
		<meta name="description" content="This is the description for this page" />
		<sec:csrfMetaTags />
		<script type="text/javascript" language="javascript">

			var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
			var csrfHeader = $("meta[name='_csrf_header']").attr("content");
			var csrfToken = $("meta[name='_csrf']").attr("content");

			// using XMLHttpRequest directly to send an x-www-form-urlencoded request
			var ajax = new XMLHttpRequest();
			ajax.open("POST", "https://www.example.org/do/something", true);
			ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded data");
			ajax.send(csrfParameter + "=" + csrfToken + "&name=John&...");

			// using XMLHttpRequest directly to send a non-x-www-form-urlencoded request
			var ajax = new XMLHttpRequest();
			ajax.open("POST", "https://www.example.org/do/something", true);
			ajax.setRequestHeader(csrfHeader, csrfToken);
			ajax.send("...");

			// using JQuery to send an x-www-form-urlencoded request
			var data = {};
			data[csrfParameter] = csrfToken;
			data["name"] = "John";
			...
			$.ajax({
				url: "https://www.example.org/do/something",
				type: "POST",
				data: data,
				...
			});

			// using JQuery to send a non-x-www-form-urlencoded request
			var headers = {};
			headers[csrfHeader] = csrfToken;
			$.ajax({
				url: "https://www.example.org/do/something",
				type: "POST",
				headers: headers,
				...
			});

		<script>
	</head>
	<body>
		...
	</body>
</html>

如果未啟用 CSRF 保護,csrfMetaTags 不輸出任何內容。