JSP Tag Libraries
Declaring the Taglib
要使用任何这些标签,您必须在您的 JSP 中声明 security 标记库:
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
The authorize Tag
此标签用于确定是否应计算其内容。在 Spring Security 3.0 中,它可以按照两种方式使用。
Spring Security 2.0 中的旧有选项也受支持,但建议不要使用。 |
第一种方法使用 web-security expression,这是在标签的 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>
一个常见的要求是仅显示特定链接,假设用户实际上被允许单击该链接。我们如何预先确定是否允许某些操作?此标签还可以采用替代模式,该模式允许您定义特定网址作为属性。如果用户被允许调用该网址,则计算标签主体。否则,则跳过它。因此,您可能拥有如下内容:
<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
的一个实例,它为提供的网址创建虚拟 Web 请求,并调用安全拦截器来查看请求是否会成功或失败。这允许您委托给您通过使用 <http>
命名空间配置中的 intercept-url
声明定义的访问控制设置,并且不必在 JSP 中重复信息(如必需的角色)。您还可以将此方法与 method
属性(提供 HTTP 方法,如 POST
)结合使用,以进行更具体的匹配。
您可以通过将 var
属性设置为变量名称,将计算标签的布尔结果(无论是授权访问还是拒绝访问)存储在页面上下文范围变量中,从而避免在页面的其他位置重复和重新计算条件的需要。
Disabling Tag Authorization for Testing
为未经授权的用户隐藏页面中的链接并不能阻止他们访问该网址。例如,他们可以将其直接键入浏览器。作为测试过程的一部分,您可能希望显示隐藏区域,以检查链接是否确实已在后端得到保护。如果您将 spring.security.disableUISecurity
系统属性设置为 true
,则 authorize
标签仍然会运行,但不会隐藏其内容。默认情况下,它还会用 <span class="securityHiddenUI">…</span>
标签将内容包围起来。这使您能够以特定的 CSS 样式(如不同的背景色)显示 “hidden” 内容。例如,尝试运行 “tutorial” 示例应用程序,并启用此属性。
如果您想更改默认 span
标签中的环绕文本(或使用空字符串将其完全删除),您还可以设置 spring.security.securedUIPrefix
和 spring.security.securedUISuffix
属性。
The authentication Tag
此标签允许访问存储在安全上下文中中的当前 Authentication
对象。它直接在 JSP 中呈现该对象的属性。因此,例如,如果 Authentication
的 principal
属性是 Spring Security 的 UserDetails
对象的一个实例,那么使用 <sec:authentication property="principal.username" />
将显示当前用户的名称。
当然,对于这类操作,没有必要使用 JSP 标签,并且有些人更希望在视图中尽可能少地包含逻辑。您可以在 MVC 控制器中访问 Authentication
对象(通过调用 SecurityContextHolder.getContext().getAuthentication()
),并将数据直接添加到模型中以供视图呈现。
The accesscontrollist Tag
本标签仅在与 Spring Security 的 ACL 模块配合使用时才有效。它会检查指定域对象所需权限的逗号分隔列表。如果当前用户拥有所有这些权限,则评估标签正文。如果他们没有权限,则跳过标签正文。
总的来说,此标签应被视为已弃用。改用 The authorize Tag。
下面的清单显示了一个示例:
<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
标签的方式相同。
The csrfInput Tag
如果启用了 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>
The csrfMetaTags Tag
如果启用了 CSRF 保护,此标签会插入包含 CSRF 保护令牌表单字段和标头名称,以及 CSRF 保护令牌值的元标签。这些元标签适用于在您应用程序的 JavaScript 中使用 CSRF 保护。
您应该将 csrfMetaTags
放置在 HTML <head></head>
块内,通常放置其他元标签的位置。一旦使用此标签,您便可以使用 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
不输出任何内容。