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。例如,他们可以直接在浏览器中输入它。作为测试过程的一部分,您可能希望显示隐藏区域,以检查链接是否确实在后端受到保护。如果您将 spring.security.disableUISecurity 系统属性设置为 true,则 authorize 标签仍会运行,但不会隐藏其内容。默认情况下,它还会将内容用 <span class="securityHiddenUI">…​</span> 标签包围。这使您可以使用特定 CSS 样式(例如不同的背景颜色)显示“隐藏”内容。例如,尝试使用启用此属性的“教程”示例应用程序运行。

您也可以设置spring.security.securedUIPrefixspring.security.securedUISuffix属性,如果您想更改默认span标签周围的文本(或者使用空字符串将其完全删除)。

身份验证标签

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

当然,没有必要为此类事情使用JSP标签,有些人更喜欢在视图中尽可能少地保留逻辑。您可以在MVC控制器中访问Authentication对象(通过调用SecurityContextHolder.getContext().getAuthentication())并将数据直接添加到您的模型中,以便视图进行渲染。

访问控制列表标签

此标签仅在与Spring Security的ACL模块一起使用时有效。它检查指定域对象的逗号分隔的必需权限列表。如果当前用户拥有所有这些权限,则评估标签主体。如果没有,则跳过它。

通常,此标签应被视为已弃用。相反,请使用授权标签

以下列表显示了一个示例

<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 保护令牌值的元标签。这些元标签对于在应用程序中的 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 不会输出任何内容。