JSP 標籤庫

宣告標籤庫

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

<%@ 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 系統屬性設定為 true,則 authorize 標籤仍然執行,但不會隱藏其內容。預設情況下,它也會用 <span class="securityHiddenUI">…​</span> 標籤包圍內容。這可讓您使用特定的 CSS 樣式 (例如不同的背景顏色) 顯示「隱藏」內容。例如,嘗試在啟用此屬性的情況下執行「教學課程」範例應用程式。

如果您想從預設的 span 標籤變更周圍文字 (或使用空字串完全移除它),您也可以設定 spring.security.securedUIPrefixspring.security.securedUISuffix 屬性。

authentication 標籤

此標籤允許存取儲存在安全上下文中目前的 Authentication 物件。它直接在 JSP 中呈現物件的屬性。因此,例如,如果 Authenticationprincipal 屬性是 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 保護,此標籤會插入 meta 標籤,其中包含 CSRF 保護令牌表單欄位和標頭名稱以及 CSRF 保護令牌值。這些 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 不會輸出任何內容。