# JSP标记库

## 宣布Taglib

要使用任何标记，你必须在JSP中声明安全性taglib:

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

## 授权标签

此标记用于确定是否应该对其内容进行评估。在 Spring Security3.0中，可以用两种方式<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnotedef_1" title="View footnote.">1</a>]</sup>。第一种方法使用[Web安全表达式](../authorization/expression-based.html#el-access-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方法，以进行更具体的匹配。

通过将`var`属性设置为变量名，可以将计算标记（无论是授予还是拒绝访问）的布尔结果存储在页面上下文范围变量中，从而避免了在页面的其他点重复和重新计算条件的需要。

### 禁用标记授权以进行测试

在页面中为未经授权的用户隐藏链接并不会阻止他们访问该URL。例如，他们可以直接在浏览器中输入。作为测试过程的一部分，你可能想要显示隐藏的区域，以检查链接是否真的在后端得到了保护。如果将系统属性`spring.security.disableUISecurity`设置为`true`，则`authorize`标记仍将运行，但不会隐藏其内容。默认情况下，它还会用`<span class="securityHiddenUI">…​</span>`标记包围内容。这允许你以特定的CSS样式（例如不同的背景颜色）显示“隐藏”内容。例如，尝试在启用此属性的情况下运行“tutorial”示例应用程序。

如果你想从默认的`span`标记中更改周围的文本（或使用空字符串完全删除它），还可以设置属性`spring.security.securedUIPrefix`和`spring.security.securedUISuffix`。

## 身份验证标记

此标记允许访问存储在安全上下文中的当前`Authentication`对象。它在JSP中直接呈现对象的属性。因此，例如，如果`Authentication`的`principal`属性是 Spring Security的`UserDetails`对象的实例，那么使用`<sec:authentication property="principal.username" />`将呈现当前用户的名称。

当然，在这种情况下没有必要使用JSP标记，有些人更喜欢在视图中尽可能少地保留逻辑。你可以访问MVC控制器中的`Authentication`对象（通过调用`SecurityContextHolder.getContext().getAuthentication()`），并将数据直接添加到模型中，以便由视图进行呈现。

## AccessControlist标签

此标记仅在与 Spring Security的ACL模块一起使用时有效。它检查指定域对象所需权限的逗号分隔列表。如果当前用户拥有所有这些权限，那么将对标记主体进行评估。如果他们不这么做，就会被跳过。一个例子可能是

|   |一般来说，这个标记应该被认为是废弃的。<br/>而不是使用[授权标签](#taglibs-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 安全自动处理 Spring 表单。

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

## CSRFmetatags标签

如果启用了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`将不输出任何内容。

---

[1](#_footnoteref_1)。还支持 Spring Security2.0中的遗留选项，但不推荐。

[Spring’s CORS Support](cors.html)[Java Configuration](../configuration/java.html)

