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
系統屬性設定為 true
,authorize
標籤仍然會執行,但不會隱藏其內容。預設情況下,它還會用 <span class="securityHiddenUI">…</span>
標籤環繞內容。這使您可以使用特定的 CSS 樣式(例如不同的背景顏色)來顯示“隱藏”內容。例如,嘗試在啟用此屬性的情況下執行“tutorial”示例應用程式。
如果您想更改環繞文字(預設是 span 標籤),您還可以設定 spring.security.securedUIPrefix
和 spring.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
例項,因此它們可以是工廠支援的任何格式。它們不必是整數。它們可以是字串,例如 READ
或 WRITE
。如果未找到 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
不輸出任何內容。