JSP标签库

本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

Spring Security有自己的taglib,它为访问安全信息和在JSP中应用安全约束提供了基本支持。

声明 Taglib

要使用任何标签,你必须在你的JSP中声明安全标签库。

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

authorize 标签

这个标签用于确定其内容是否应该被评估。在Spring Security 3.0中,它可以以两种方式使用。

Spring Security 2.0中的传统选项也被支持,但不鼓励使用。

第一种方法使用 web-security 表达式,它被指定在标签的 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>

要使用这个标签,你必须在你的 application context 中也有一个 WebInvocationPrivilegeEvaluator 的实例。如果你使用的是命名空间(namespace),就会自动注册一个。这是一个 DefaultWebInvocationPrivilegeEvaluator 的实例,它为所提供的URL创建一个假的Web请求,并调用安全拦截器以查看该请求是否成功。这让你可以委托给你在 <http> 命名空间配置中使用 intercept-url 声明所定义的访问控制设置,并且省去了在JSP中重复信息的麻烦(比如所需的角色)。你也可以将这种方法与 method 属性(提供HTTP方法,如 POST)结合起来,进行更具体的匹配。

你可以通过将 var 属性设置为变量名,将评估标签的Boolean结果(是授予还是拒绝访问)存储在一个页面上下文范围变量中,从而避免在页面的其他点上重复和重新评估条件。

禁用标签授权进行测试

为未经授权的用户隐藏页面中的链接并不能阻止他们访问该URL。例如,他们可以直接在他们的浏览器中输入它。作为测试过程的一部分,你可能想揭示隐藏的区域,以检查链接在后端是否真的安全。如果你将 spring.security.disableUISecurity 系统属性设置为 trueauthorize 标签仍然运行,但不会隐藏其内容。默认情况下,它还会用 <span class="securityHiddenUI">…​</span> 标签包裹内容。这让你可以用特定的CSS样式显示 “hidden” 的内容,比如不同的背景颜色。试着运行 “tutorial” 示例应用程序,例如,启用该属性。

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

authentication 标签

这个标签允许访问存储在 security context 的当前 Authentication 对象。它直接在JSP中渲染该对象的一个属性。因此,例如,如果 Authenticationprincipal 属性是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>

权限被传递给 application context 中定义的 PermissionFactory,将它们转换为ACL Permission 实例,所以它们可以是工厂支持的任何格式。它们不一定是整数。它们可以是字符串,如 READWRITE。如果没有找到 PermissionFactory,就会使用 DefaultPermissionFactory 的一个实例。来自应用 application context 的 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保护,这个标签会插入 meta 标签,其中包含CSRF保护令牌的表单字段和header名称以及CSRF保护令牌值。这些元标签对于在你的应用程序的JavaScript中采用CSRF保护非常有用。

你应该把 csrfMetaTags 放在HTML <head></head> 块中,也就是你通常会放置其他 meta 标签的地方。一旦你使用了这个标签,你就可以通过使用JavaScript来访问表单字段名、header名和标记值。在这个例子中使用了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 不输出任何东西。