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 系统属性设置为 trueauthorize 标签仍然会运行,但不会隐藏其内容。默认情况下,它还会用 <span class="securityHiddenUI">…​</span> 标签环绕内容。这使您可以使用特定的 CSS 样式(例如不同的背景颜色)来显示“隐藏”内容。例如,尝试在启用此属性的情况下运行“tutorial”示例应用程序。

如果您想更改环绕文本(默认是 span 标签),您还可以设置 spring.security.securedUIPrefixspring.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 实例,因此它们可以是工厂支持的任何格式。它们不必是整数。它们可以是字符串,例如 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 保护,此标签会插入包含 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 不输出任何内容。