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.securedUIPrefixspring.security.securedUISuffix 属性。

The authentication Tag

此标签允许访问存储在安全上下文中中的当前 Authentication 对象。它直接在 JSP 中呈现该对象的属性。因此,例如,如果 Authenticationprincipal 属性是 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 实例,以便可以采用工厂支持的任何格式。它们不必是整数。它们可以是字符串,如 READWRITE。如果没有找到 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 不输出任何内容。