Spring Security 参考手册(二)

2020年08月05日 阅读数:61
这篇文章主要向大家介绍Spring Security 参考手册(二),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

受权

在Spring Security的高级受权功能是其受欢迎的最有说服力的缘由之一,不管您如何选择如何进行身份验证-是否使用提供的机制和提供程序的Spring Security,或整合与一个容器或其余non-Spring Security 认证机构-你会发现受权服务能够在您的应用程序中使用一个一致的和简单的方式.javascript

在这一部分咱们将探讨不一样的` abstractsecurityinterceptor `实现,在第一部分介绍.而后,咱们将继续探索如何经过使用域访问控制列表微调受权.html

受权体系结构

受权

正如咱们在<<技术授予权,技术综述 >>所看到,全部的Authentication实现存储的列表GrantedAuthority对象.这些表明已被授予主要的的当局. GrantedAuthority对象是由` authenticationManager 插入到`Authentication 对象,而后读取 AccessDecisionManager作出判断.java

GrantedAuthority是一个只有一个方法的接口node

String getAuthority();

这个方法容许AccessDecisionManager 来判断获得一个精确的String表示的` GrantedAuthority .经过返回一个表示做为一个`String,一个` GrantedAuthority 能够很容易的经过`AccessDecisionManager 来read,若是一个` GrantedAuthority 不能精确地表示为一个`String,` GrantedAuthority 将会被认为是"complex"和`getAuthority() 必须返回为null.mysql

"complex" GrantedAuthority的一个将一个应用于不一样客户账户号码的操做和权限阈值的列表的实现例子.表明这个复杂的` GrantedAuthority 做为`String将是至关困难的,做为一个结果,` getauthority() 方法应该返回`null.这将对任何` accessDecisionManager 代表它须要明确的支持 GrantedAuthority `实施以了解其内容.git

Spring Security包括一个具体的` GrantedAuthority 实施, grantedauthorityimpl .这容许用户指定的任何String转换成一种` GrantedAuthority .全部的 AuthenticationProvider 的包括与安全架构使用 grantedauthorityimpl`填充Authentication对象.github

Pre-Invocation处理

正如咱们在<<安全对象、技术综述>>章节中也看到过的,Spring Security,提供拦截控制访问安全对象如方法调用或Web请求。是否容许进行调用前调用的决定是由`AccessDecisionManager `做出判断.web

访问决策管理器

` accessDecisionManager  abstractsecurityinterceptor 和负责制定最终的访问控制决策.`AccessDecisionManager接口包含三种方法:ajax

void decide(Authentication authentication, Object secureObject,
	Collection<ConfigAttribute> attrs) throws AccessDeniedException;

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);

AccessDecisionManagerdecide方法传递了它所须要的全部相关信息,以做出受权决策.尤为,经过安全的“对象”,使这些参数包含在实际的安全对象调用中进行检查.例如,让咱们假设安全对象是一个MethodInvocation `资料,这将是很容易实现`MethodInvocation对于任何Customer论点.而后执行某种安全逻辑判断、来确保AccessDecisionManager `主容许对客户操做.若是访问被拒绝并抛出`AccessDeniedException 咱们的预期就实现了.正则表达式

若是` accessDecisionManager 能够处理经过 configattribute ,`supports(ConfigAttribute)方法由AbstractSecurityInterceptor 在决定启动时候命名. supports(Class) 方法被安全拦截器实现,确保配置` accessDecisionManager `支持类型的安全对象的被拦截.

Voting-Based访问决策管理器实现

同时,用户能够实现本身的` AccessDecisionManager`判断、控制受权的全部方面,Spring Security包括几个基于投票的` accessDecisionManager `实现. Voting Decision Manager说明相关类.

access decision voting.png
Figure 2. Voting Decision Manager

使用这种方法,一系列的` accessdecisionvoter 实现调查受权决策. accessDecisionManager 而后决定是否抛出accessdeniedexception `基于其选票的评估。

AccessDecisionVoter接口包含三种方法:

int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);

具体返回一个int,可能反映在` accessdecisionvoter 的静态字段 access_abstain  access_denied  access_granted .若是对受权决策没有意见一个投票的实施将返回 access_abstain . 若是真的有一个观点,它必须返回 access_denied access_granted `.

这里三个具体的AccessDecisionManager提供了符合投票的 Spring Security,` consensusbased 实施将授予或拒绝基于非共识的弃权票的访问.提供的属性来控制在一个平等的投票活动的行为,或者若是全部的选票都弃权. affirmativebased 实施将会受权访问若是你个或者更多的`ACCESS_GRANTED 投票被收到(即便投票被忽略,也至少有一个投票).像“ConsensusBased”实现,有一个参数,控制行为若是全部选民弃权.UnanimousBased的提供者预计一致ACCESS_GRANTED的选票以授予访问权限,忽略了自制。它会拒绝访问若是有任何“ACCESS_DENIED”投票.像其余实现,有一个参数,控制行为若是全部选民弃权.

能够实现自定义` accessDecisionManager 计算选票不一样。例如,从一个特定的 accessdecisionvoter `可能会获得额外的加权投票,而否定从一个特定的选民投票可能有否决权的影响.

角色选民

最经常使用的由Spring Security提供的AccessDecisionVoter 是简单的RoleVoter,若是用户已被分配该角色,将配置属性视为简单的角色名称和投票授予访问权限.

若是ConfigAttribute 带着前缀ROLE_开始将会进行投票,它将投票授予访问权限,若是有` GrantedAuthority 它返回一个`String表示(经过` getauthority() 方法)刚好等于一个或多个从前缀 role_  configattributes .若是没有从 role_ 精确匹配任何 configattribute  rolevoter 会投票拒绝访问。若是 role_ 没有开始 configattribute `,选民将投弃权票。

通过身份验证的选民

另外一个选民,咱们从 AuthenticatedVoter看到,能够用来区分匿名,fully-authenticated,记得我经过身份验证的用户,许多网站容许某些有限的访问在记得我认证,可是须要用户确认他们的身份登陆的彻底访问.当咱们使用属性IS_AUTHENTICATED_ANONYMOUSLY授予匿名访问,这个属性是由“AuthenticatedVoter”进行处理。有关更多信息,请参见这个类的Javadoc.

定制的选民

显然,您还能够实现自定义“AccessDecisionVoter”,你能够把任何你想要访问控制逻辑.这多是特定于应用程序(业务逻辑相关)或可能实现一些安全管理逻辑,例如你会发现 blog article 在Spring web网站描述如何使用实时选民拒绝访问用户的帐户被暂停.

调用处理

而“AccessDecisionManager”是由“AbstractSecurityInterceptor”在继续以前调用安全对象调用.某些应用程序须要一种方法修改对象的实际安全返回的对象调用.同时您能够很容易地实现本身的AOP实现这一担心, Spring Security提供了一个方便的钩,几个集成ACL的功能的具体实现.

After Invocation Implementation说明了Spring Security的AfterInvocationManager 以及这个具体实现.

after invocation.png
Figure 3. After Invocation Implementation

像Spring Security的其余部分,AfterInvocationManager 有一个具体的实现,AfterInvocationProviderManager调查AfterInvocationProvider的表,每个AfterInvocationProvider容许修改返回对象或抛出AccessDeniedException.的确多个提供者能够修改对象,如以前的供应商的结果传递给下一个列表中.

请注意,若是您正在使用AfterInvocationManager,你仍然须要配置属性,使MethodSecurityInterceptorAccessDecisionManager容许一个操做.若是您使用的是典型的Spring Security包括“AccessDecisionManager”实现,没有配置属性定义为一个特定的安全方法调用将致使每一个“AccessDecisionVoter”投弃权票,相反,若是AccessDecisionManager 性能 “allow IfAllAbstainDecisions”是false就会抛出一个 AccessDeniedException,你能够经过设置“allowIfAllAbstainDecisions”避免这种潜在的问题改变为true(虽然这是通常不推荐),或者(ii)只是确保至少有一个配置属性,一个“AccessDecisionVoter”将投票受权访问,后者(推荐)的方法一般是经过“ROLE_USER”或“ROLE_AUTHENTICATED”配置属性.

层次的角色

它是一个共同的要求,一个特定的应用程序中的角色应该自动"include"其余角色,例如,在一个应用程序中有一个"admin" 和"user"的角色的概念,你可能但愿一个管理员可以尽一切正常的用户能够。要作到这一点,你能够确保全部的管理用户也被分配到"user"的角色.另外,您能够修改每个访问约束,这须要"user"的角色,还包括"admin"的做用.这可能会变得至关复杂,若是你有不少不一样的角色在你的应用程序.

使用角色层次结构容许您配置哪些角色(或主管)应包括其余角色(或主管部门).一个额外的of Spring Security’s RoleVoter的版本,RoleHierarchyVoter配置了一个` rolehierarchy `,从它得到全部的"reachable authorities",用户被分配。一个典型的配置可能看起来像这样:

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
	<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
		class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
	<property name="hierarchy">
		<value>
			ROLE_ADMIN > ROLE_STAFF
			ROLE_STAFF > ROLE_USER
			ROLE_USER > ROLE_GUEST
		</value>
	</property>
</bean>

在这里,咱们有四个角色在一个层次结构 ROLE_ADMIN ⇒ ROLE_STAFF ⇒ ROLE_USER ⇒ ROLE_GUEST.经过身份验证的用户ROLE_ADMIN, 要表现得好像他们全部的四种角色在安全约束的评价与判断,要表现得好像他们全部的四种角色在安全约束的评价与判断,AccessDecisionManager 配置上述RoleHierarchyVoter.>符号能够被认为是意义的"includes".

角色层次结构提供了一个方便的方法简化了您的应用程序的访问控制配置数据和/或减小您须要分配给用户的权限数.对于更复杂的要求,您可能但愿定义您的应用程序所需的特定访问权限和被分配给用户的角色之间的逻辑映射,在加载用户信息时将二者翻译成二者之间的关系.

安全对象的实现

AOP联盟(方法调用)安全拦截器

Spring Security 2.0以前,确保`MethodInvocation`资料须要至关多的配置.如今方法安全的推荐方法是使用< <ns-method-security,namespace configuration>>.这种方法的安全基础设施beans是为您自动配置的,因此您不须要知道实现类的状况。咱们将提供一个在这里涉及的类的快速概述。

方法在执行安全使用` methodsecurityinterceptor ,这是一个固定的`MethodInvocation .根据配置的方法,一个拦截多是特定的一个单一的bean或多个beans之间的共享.拦截器使用` methodsecuritymetadatasource 实例获取配置属性,适用于一个特定的方法调用.`MapBasedMethodSecurityMetadataSource用于存储配置属性的键控的方法名称(能够使用通配符),将在内部使用时,这些属性定义在应用程序的上下文中使用的<intercept-methods>拦截或<protect-point>元素。

固然你能够使用一个Spring AOP的代理机制配置一个` methodsecurityiterceptor `直接应用程序上下文中:

<bean id="bankManagerSecurity" class=
	"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
	<sec:method-security-metadata-source>
	<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
	<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
	</sec:method-security-metadata-source>
</property>
</bean>

AspectJ(链接点)安全拦截器

AspectJ的安全拦截器是AOP联盟安全拦截器在上一节讨论很是类似。事实上,咱们将只讨论在这一部分的差别.

AspectJ拦截器被命名为 AspectJSecurityInterceptor.不像AOP联盟安全拦截器,它依赖于Spring应用程序上下文编织的安全拦截器经过代理,AspectJSecurityInterceptor是基于AspectJ编译器.不会罕见的在同一个程序中使用的两种安全拦截器,与AspectJSecurityInterceptor用于域对象实例安全,AOP联盟` methodsecurityinterceptor `用于服务层安全.

让咱们首先考虑的是如何AspectJSecurityInterceptor配置在Spring应用程序上下文:

<bean id="bankManagerSecurity" class=
	"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
	<sec:method-security-metadata-source>
	<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
	<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
	</sec:method-security-metadata-source>
</property>
</bean>

正如你所看到的,除了类名称,AspectJSecurityInterceptor是彻底同样的AOP联盟安全拦截器.事实上,两个拦截器能够共享相同的` securitymetadatasource ,做为 securitymetadatasource 做品 `java.lang.reflect.Method而不是AOP库类。固然,你访问的决定得到有关特定AOP库调用(即` MethodInvocation 或`JoinPoint),这样能够使访问的决定时,考虑的范围以外的标准(如方法的参数).

下次你须要定义一个AspectJ aspect.例如:

package org.springframework.security.samples.aspectj;

import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;

public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {

	private AspectJSecurityInterceptor securityInterceptor;

	pointcut domainObjectInstanceExecution(): target(PersistableEntity)
		&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);

	Object around(): domainObjectInstanceExecution() {
		if (this.securityInterceptor == null) {
			return proceed();
		}

		AspectJCallback callback = new AspectJCallback() {
			public Object proceedWithObject() {
				return proceed();
			}
		};

		return this.securityInterceptor.invoke(thisJoinPoint, callback);
	}

	public AspectJSecurityInterceptor getSecurityInterceptor() {
		return securityInterceptor;
	}

	public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
		this.securityInterceptor = securityInterceptor;
	}

	public void afterPropertiesSet() throws Exception {
		if (this.securityInterceptor == null)
			throw new IllegalArgumentException("securityInterceptor required");
		}
	}
}

在上面的例子中,安全拦截器将被应用到每个实例` persistableentity ,这是一个抽象类没有显示(你能够使用任何其余类或`pointcut表达你喜欢).对于那些好奇的人,` aspectjcallback 是由于 proceed();声明具备特殊的意义只有在 around() 体。当它想要的目标继续,`AspectJSecurityInterceptor 调用这个匿名` aspectjcallback `类.

你须要配置Spring 负载方面和链接AspectJSecurityInterceptor。一个实现这一的bean声明以下所示:

<bean id="domainObjectInstanceSecurityAspect"
	class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
	factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>

是这么回事!如今你能够从你的应用程序中的任何地方建立你的豆子,使用任何你认为合适的方式(eg new Person();)他们会拥有安全拦截器的应用

表达式的访问控制

Spring Security 3.0介绍了使用的能力,做为一个受权机制,除了简单的使用配置属性和访问决策的选民,之前见过的使用弹簧的表达。基于表达式的访问控制是创建在相同的架构,但容许复杂的布尔逻辑被封装在一个单一的表达.

概述

Spring Security 使用Spring EL来支持,你应该看看如何,若是你有兴趣在更深刻了解主题。表达式是用"root object" 评估的,做为评价上下文的一部分。Spring Security使用特定的类用于Web和方法安全做为根对象,以提供内置表达式和访问当前主体的值等.

常见的内置的表达式

表达根对象的基类是` securityexpressionroot `.这提供了一些常见的表达式,可应用在网络和方法安全性.

Table 3. Common built-in expressions
表达 描述

hasRole([role])

若是当前主体具备指定的角色,则返回true.默认状况下,若是提供的角色不从'ROLE_'这里提供,这将增长。这能够经过修改` defaultroleprefix  defaultwebsecurityexpressionhandler `配置.

hasAnyRole([role1,role2])

若是当前的主体有任何提供的角色(给定的做为一个逗号分隔的字符串列表)的话,返回true,默认状况下,若是提供的角色不从 'ROLE_',这将增长。这能够经过修改` defaultroleprefix defaultwebsecurityexpressionhandler `定制.

hasAuthority([authority])

若是当前的主体具备指定的权限,则返回 true.

hasAnyAuthority([authority1,authority2])

若是当前的主体有任何提供的角色(给定的做为一个逗号分隔的字符串列表)的话,返回true.

principal

容许直接访问表示当前用户的主对象

authentication

容许直接访问从SecurityContext得出当前的Authentication对象

permitAll

老是评估为true

denyAll

老是评估为false

isAnonymous()

若是当前的主体是一个匿名用户,则返回true.

isRememberMe()

若是当前的主体是一个匿名用户,则返回true

isAuthenticated()

若是用户不是匿名的,则返回 true

isFullyAuthenticated()

若是用户不是一个匿名的或是一个记住个人用户返回true

hasPermission(Object target, Object permission)

若是用户已访问给定权限的提供的目标,则返回true,例如hasPermission(domainObject, 'read')

hasPermission(Object targetId, String targetType, Object permission)

若是用户已访问给定权限的提供的目标,则返回true,例如hasPermission(1, 'com.example.domain.Message', 'read')

Web Security Expressions

使用表达式来保护我的网址,首先须要设置“use-expressions”属性的< http >为true.Spring Security预期的“访问”属性的< intercept-url >元素包含Spring EL表达式。一个布尔表达式应该评估,定义是否应该容许访问. 例如:

<http>
	<intercept-url pattern="/admin*"
		access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
	...
</http>

这里咱们定义了应用程序的“admin”区域(定义的URL模式)只能提供给用户授予机关“admin”,其IP地址匹配本地子网.在前一节中咱们已经看到内置hasRole表达式。表达“hasIpAddress”是另外一个内置的表达式是特定于网络安全.这由WebSecurityExpressionRoot下定义,一个实例时用做表达式根对象评估web访问表达式。这个对象也直接暴露的HttpServletRequest对象的名字“请求”,这样你就能够直接调用请求在一个表达式。若是正在使用表情,“WebExpressionVoter”将被添加到“AccessDecisionManager”所使用的名称空间. 若是你不使用名称空间和想使用表情,你必须添加一个配置.

在网络安全bean表达式

若是你想扩展表达式可用,您能够很容易地操做任何你暴露的Spring Bean。例如,assumming你有一个Bean的名称“webSecurity”包含如下方法

public class WebSecurity {
		public boolean check(Authentication authentication, HttpServletRequest request) {
				...
		}
}

你能够参考使用方法:

<http>
	<intercept-url pattern="/user/**"
		access="@webSecurity.check(authentication,request)"/>
	...
</http>

或在Java配置

http
		.authorizeRequests()
				.antMatchers("/user/**").access("@webSecurity.check(authentication,request)")
				...

Path Variables in Web Security Expressions

有时在一个URL它很好可以参考路径变量. 例如,考虑一个RESTful应用程序从URL路径的格式查找用户id`/user/{userId}`.

你能够很容易地将参考路径变量的模式.例如,若是你有一个Bean的名称“webSecurity”包含如下:

public class WebSecurity {
		public boolean checkUserId(Authentication authentication, int id) {
				...
		}
}

你能够参考使用方法:

<http>
	<intercept-url pattern="/user/{userId}/**"
		access="@webSecurity.checkUserId(authentication,#userId)"/>
	...
</http>

或在Java配置

http
		.authorizeRequests()
				.antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
				...

在这两个配置相匹配的url将经过path变量(和)转换成checkUserId方法.

例如,若是这个URLs是 /user/123/resource,id是123.

Method Security Expressions

方法安全性是一个更复杂的比一个简单的规则容许或拒绝,Spring Security 3.0介绍了一些新的注释,以便全面支持表达式的使用.

@Pre and @Post Annotations

有四个属性注释支持表达式容许pre和post-invocation受权检查并提交支持过滤收集参数或返回值.他们是@PreAuthorize@PreFilter@PostAuthorize and @PostFilter. 它们的使用是经过“global-method-security”名称空间的元素:

<global-method-security pre-post-annotations="enabled"/>
使用@PreAuthorize和@PostAuthorize访问控制,最明显的是有用的注释是“@PreAuthorize”决定是否能够被调用方法。例如(从"Contacts"示例应用程序)
@PreAuthorize("hasRole('USER')")
public void create(Contact contact);

这意味着用户与角色"ROLE_USER"才会容许访问.显然一样的事情能够很容易地经过使用传统的配置和一个简单的配置属性所需的角色:

@PreAuthorize("hasPermission(#contact, 'admin')")
public void deletePermission(Contact contact, Sid recipient, Permission permission);

这里咱们使用一个方法参数的表达式来决定当前用户是否有"admin"容许给定的接触。内置的hasPermission()表达式是经过应用程序上下文连接到Spring Security ACL模块,see below,你能够访问任何变量名称做为方法参数的表达式.

有不少方式Spring Security能够解决方法参数。Spring Security使用DefaultSecurityParameterNameDiscoverer发现参数名称。默认状况下,下列选项尝试方法做为一个总体.

  • 若是Spring Security的@P注释存在一个参数的方法,将使用价值。这是使用JDK JDK 8以前有用的接口,编译不包含任何有关参数名称的信息。例如:

    import org.springframework.security.access.method.P;
    
    ...
    
    @PreAuthorize("#c.name == authentication.name")
    public void doSomething(@P("c") Contact contact);

    在幕后使用使用“AnnotationParameterNameDiscoverer”可实现自定义支持value属性指定的任何注释.

  • 若是Spring Data'的@Param注释存在至少一个参数的方法,将使用价值。这是使用JDK JDK 8以前有用的接口,编译不包含任何有关参数名称的信息。例如:

    import org.springframework.data.repository.query.Param;
    
    ...
    
    @PreAuthorize("#n == authentication.name")
    Contact findContactByName(@Param("n") String name);

在幕后使用使用“AnnotationParameterNameDiscoverer”可实现自定义支持value属性指定的任何注释.

  • 若是JDK 8是用来编译源参数的参数和使用Spring 4+,那么标准JDK反射API用于发现参数名称。这包含两类和接口工做.

  • 最后,若是代码编译与调试符号,参数名称将被发现使用调试符号。这不会为接口工做,由于他们没有调试信息参数名称。为接口,必须使用注释或JDK 8的方法.

任何Spring-EL功能可在表达,因此你也能够访问属性参数。举个例子,若是你想要一个特定方法只容许一个用户访问的用户名匹配的接触,你能够写

@PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);

咱们访问另外一个内置的表情, authentication,也就是 Authentication存储在安全上下文。您也能够直接访问它的principal属性,使用表达式principal。值每每会是一个“UserDetails”实例,因此你可能会使用一个表达式principal.username或“principal.enabled”.

通常,您可能但愿执行访问控制检查方法调用以后。这能够经过使用@PostAuthorize注释.访问一个方法的返回值,使用内置的名字“returnObject”的表示

过滤用@PreFilter and @PostFilter

正如你可能已经知道,Spring Security支持集合和数组的过滤,这能够经过使用表达式。这是最多见的一个方法的返回值上执行。例如

@PreAuthorize("hasRole('USER')")
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")
public List<Contact> getAll();

当用@PostFilter 注释,Spring Security遍历返回的集合并删除任何元素提供的表达式是错误的。“filterObject”指的是当前的对象的集合。你还能够过滤方法调用以前,使用“@PreFilter”,尽管这是一个不太常见的需求。语法是相同的,可是若是有一个以上的论证它是一个集合类型而后你必须选择一个的名字使用“filterTarget”属性的注释.

注意,过滤显然是不能代替调优数据检索查询。若是你是过滤大收藏和删除的条目,那么这多是低效的.

内置的表达式

有一些内置的表达式具体方法安全,咱们已经看到在上面使用。filterTarget 和returnValue值是很简单,但使用hasPermission()的表达式权证更仔细的观察.

许可评估者接口

hasPermission()的表达式是委托给一个实例的PermissionEvaluator.它旨在表达系统和Spring Security的ACL系统之间的桥梁,容许您指定受权约束域对象,基于抽象的权限.没有显式的依赖ACL模块,因此你能够互换,若是须要另外一个实现。接口有两个方法:

boolean hasPermission(Authentication authentication, Object targetDomainObject,
							Object permission);

boolean hasPermission(Authentication authentication, Serializable targetId,
							String targetType, Object permission);

这直接映射到可用的版本的表情,除了那第一个参数( Authentication 的对象)是不提供的。首先是在域对象的状况下,使用的访问控制,已经加载。而后表达式将返回true,若是当前用户拥有该对象的批准。第二个版本是用于装载状况下,对象不是,可是它的标识符。域对象的抽象的"type"说明符也是必需的,容许加载正确的ACL权限。这从来是对象的Java类,可是这不是必须的,只要符合权限如何加载就能够.

使用“hasPermission()的表情,必须在您的应用程序上下文配置一个PermissionEvaluator”.这看起来像这样:

<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>

<bean id="expressionHandler" class=
"org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
	<property name="permissionEvaluator" ref="myPermissionEvaluator"/>
</bean>

在“myPermissionEvaluator”是实现“PermissionEvaluator”bean。一般这将从ACL实现模块叫作“AclPermissionEvaluator”。见"Contacts"示例应用程序配置更多的细节.

方法安全性元注释

你能够使用元数据注释方法安全性提升代码的可读性。

若是你发现你是在代码库重复相同的复杂表达式。尤为方便

例如,考虑如下几点

@PreAuthorize("#contact.name == authentication.name")

Instead of repeating this everywhere, we can create a meta annotation that can be used instead.

@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("#contact.name == authentication.name")
public @interface ContactPermission {}

元注释可用于任何Spring安全方法的安全注释.

为了保持符合jsr - 250规范的注释不支持元注释.

额外的话题

在本部分中,咱们将介绍功能,这须要一个前一章节的知识以及一些更高级的和不常使用的功能框架。

域对象的安全(acl)

概述

复杂的应用须要的每每不是简单的获得在web请求或方法调用级别来定义访问权限。而是,安全决议须要包括谁(认证),其中(的MethodInvocation)和什么(一些领域对象)。换句话说,受权决策还须要考虑一个方法调用的实际域对象实例的主题。

想象你正在设计申请宠物诊所。将会有两个主要基于spring的应用程序的用户组:宠物诊所的工做人员,以及宠物诊所的客户。员工将得到的全部数据,而你的客户只能看到本身的客户记录。使它更有趣,你的客户可让其余用户看到他们的客户记录,例如"puppy preschool"的导师或当地的"Pony Club"的总统。使用Spring安全为基础,有几种方法能够使用:

  • 写下你的业务方法执行的安全。你能够咨询一个集合内的Customer域对象实例来肯定哪些用户能够访问。经过使用SecurityContextHolder.getContext().getAuthentication(),你将可以访问Authentication的对象.

  • 写一个 AccessDecisionVoter执行的安全GrantedAuthority[]存储在Authentication对象。这将意味着你的AuthenticationManager须要填充的Authentication自定义GrantedAuthority[]表明每个Customer访问域对象实例.

  • 写一个AccessDecisionVoter 执行安全和直接打开目标客户的域对象。这将意味着你的选民须要访问一个DAO,容许它来检索Customer 的对象。它将访问的Customer 对象的集合的批准用户和作出适当的决定.

每个这些方法是彻底合法的。然而,第一对受权检查你的业务代码。主要问题包括加强的困难的单元测试和重用会更困难的Customer受权逻辑。得到“GrantedAuthority[]的从Authentication对象也很好,但不会扩展到大量的Customer。若是用户能够访问5000`Customer`(不可能在这种状况下,但试想一下,若是它是一个受欢迎的兽医大小马俱乐部!)所需的内存消耗和时间来构造对象将是不受欢迎的Authentication。最后的方法,直接从外部代码打开Customer,多是最好的三个。实现关注点分离,不滥用内存或CPU周期,但它仍然是低效的,“AccessDecisionVoter”和最终的商业方法自己将执行调用DAO负责检索AccessDecisionVoter对象。两个访问每一个方法调用显然是不可取的。此外,每一个方法列出你须要编写本身的访问控制列表(ACL)从头持久性和业务逻辑.

幸运的是,还有另外一个选择,咱们下面会讲到.

关键概念

Spring Security的ACL服务运送spring-security-acl-xxx.jar.您须要将这个JAR添加到类路径中使用Spring安全域对象实例的安全功能.

Spring Security的域对象实例的安全能力中心的概念一个访问控制列表(ACL)。每一个域对象实例系统中有本身的ACL,和ACL记录的细节,谁能和不能使用域对象。有鉴于此,Spring Security提供三个主要ACL-related功能应用程序:

  • 一种有效地检索ACL条目你全部的域对象(和修改ACL).

  • 确保给定的方式主要是容许的工做与你的对象,以前被称为方法.

  • 确保给定的方式主要是容许使用对象(或者他们返回),后被称为方法.

第一个要点,Spring Security ACL的的一个主要功能模块提供了一个高性能的方式检索ACL。这个ACL库能力是极其重要的,由于每个域对象实例系统中可能有多个访问控制条目,而且每一个ACL可能继承其余树形结构中的ACL(这是开箱即用的支持由Spring Security,很是经常使用)。Spring Security的ACL能力都是被仔细设计以提供高性能检索ACL,加上可插入的缓存,deadlock-minimizing数据库更新、独立于ORM框架(咱们直接使用JDBC),适当的封装,和透明的数据库更新.

给定数据库ACL的操做模块的核心,让咱们探索使用四个主要表的默认实现。下面表的大小在一个典型的Spring Security ACL部署,最后列出的表行:

  • ACL_SID容许咱们惟一地标识系统中的任何本金或权威("SID" 表明"security identity")。惟一列ID、文本表示的SID,国旗代表是否文本表示是指主体名称或GrantedAuthority.所以,有一个为每一个独特的主体或GrantedAuthority行。的上下文中使用时得到许可,SID一般称为"recipient".

  • ACL_CLASS容许咱们惟一地标识系统中任何域对象类。只列ID和Java类名。所以,有一行咱们但愿每个独特的类存储ACL权限.

  • ACL_OBJECT_IDENTITY门店信息系统中每一个独特的域对象实例。列包含ID,ACL_CLASS表的外键,因此咱们知道惟一标识符ACL_CLASS实例咱们提供信息,父,ACL_SID表的外键表示域对象实例的全部者,以及咱们是否容许ACL条目继承任何父ACL。咱们已经为每一个域对象实例一行咱们存储ACL权限.

*最后,ACL_ENTRY存储我的权限分配给每一个收件人。ACL_OBJECT_IDENTITY列包括一个外键,收件人ACL_SID(外键),是否咱们将审计,整数位屏蔽表明实际的权限被授予或拒绝。咱们为每一个收件人接收一行容许使用一个域对象.

如最后一段中所述,ACL系统使用整数位屏蔽。别担忧,你不须要知道的细微之处,转向使用ACL系统,可是我想说的是,咱们有32位咱们能够打开或关闭。每个位表明一个许可,并默认权限阅读(0),写(1),建立(2)、删除(第3位)和管理(4)。很容易实现本身的“许可”实例若是你但愿使用其余权限,和其他的ACL框架将没有知识的扩展.

重要的是要理解,域对象的数量在系统彻底没有影响咱们选择使用整数位屏蔽。虽然你有32位用于权限,你能够有数十亿的域对象实例(这将意味着数十亿行ACL_OBJECT_IDENTITY并且极可能ACL_ENTRY)。咱们这一点,由于咱们发现有时人们错误地认为他们须要一点对于每个可能的域对象,这并不是如此.

如今咱们已经提供了一个基本的概述ACL系统作什么,看起来在一个表结构,让咱们探索的关键接口。关键接口:

  • Acl:每个域对象都有且只有一个Acl的对象,内部持有AccessControlEntry的年代以及知道的Acl的全部者。Acl不直接引用到域对象,而是一个ObjectIdentity.Acl的存储在ACL_OBJECT_IDENTITY表.

  • AccessControlEntry:一个Acl拥有多个“AccessControlEntry”年代,一般缩写为ace框架。每一个ACE是指一个特定的元组的“许可”,“Sid”和“Acl”。ACE还能够授予或non-granting和包含审计设置。ACE ACL_ENTRY表中存储。

  • Permission:权限表明一个特定不变的位元遮罩,为钻头提供了便利的函数屏蔽和输出信息。上面给出的基本权限(字节0到4)中包含“BasePermission”类。

  • Sid:ACL模块须要指校长和“GrantedAuthority[]的年代。提供了一个间接层的Sid的界面,这是一种“安全标识”的缩写。常见的类包括“PrincipalSid”(表明校长在一个“身份验证”对象)和“GrantedAuthoritySid”。安全身份信息存储在ACL_SID表。

  • ObjectIdentity:每一个域对象内部ACL表示模块由一个“ObjectIdentity”。默认实现叫作“ObjectIdentityImpl”。

  • AclService:检索Acl的适用于一个给定的“ObjectIdentity”。包括实现(JdbcAclService),检索操做委托给一个“LookupStrategy”。“LookupStrategy”为检索ACL信息提供了一个高度优化的策略,使用“(BasicLookupStrategy”批处理检索)和支持自定义实现利用物化视图,分级查询和performance-centric类似,non-ANSI SQL功能。

  • MutableAclService:容许提出了修改Acl的持久性。这并非最重要的若是你不但愿使用这个接口。

请注意咱们的开箱即用的AclService和相关数据库类都使用ANSI SQL.这是主要的数据库.在写这篇文章的时候,系统已经成功测试了使用超音速SQL,PostgreSQL,Microsoft SQL Server和Oracle.

两个样本船与演示Spring Security ACL模块。第一个是联系人样本,另外一个是文档管理系统(DMS)样本。咱们建议采起一看这些例子.

开始

要开始使用Spring Security ACL的功能,你须要你的ACL信息存储在某个地方。这须要实例化的DataSource使用Spring。DataSource而后注入JdbcMutableAclServiceBasicLookupStrategy 实例。后者提供高性能的ACL检索功能,和前提供增变基因功能。指的一个样本船与Spring Security配置的一个示例。您还须要用四个ACL-specific填充数据库表中列出的最后一部分(参见ACL样本的适当的SQL语句).

一旦您建立了所需的模式和实例化JdbcMutableAclService,接下来将须要确保您的域模型支持互操做性的Spring Security ACL包。但愿ObjectIdentityImpl 将是足够的,由于它提供了大量的方法能够使用它。大部分人都有包含 public Serializable getId()的方法。若是返回类型是长,或兼容长(例如int),你会发现你不须要提供进一步的考虑ObjectIdentity问题。许多地方的ACL模块依赖长标识符。若是你不使用长(或int,字节等),有一个很是好的机会你须要从新实现的类。咱们不打算支持非long标识符在Spring Security的ACL模块,多头已经兼容全部数据库序列,最多见的标识符的数据类型和长度足够容纳全部常见的使用场景。

如下代码片断显示了如何建立一个Acl,或修改现有Acl:

// Prepare the information we'd like in our access control entry (ACE)
ObjectIdentity oi = new ObjectIdentityImpl(Foo.class, new Long(44));
Sid sid = new PrincipalSid("Samantha");
Permission p = BasePermission.ADMINISTRATION;

// Create or update the relevant ACL
MutableAcl acl = null;
try {
acl = (MutableAcl) aclService.readAclById(oi);
} catch (NotFoundException nfe) {
acl = aclService.createAcl(oi);
}

// Now grant some permissions via an access control entry (ACE)
acl.insertAce(acl.getEntries().length, p, sid, true);
aclService.updateAcl(acl);

在上面的示例中,咱们检索ACL的44号"Foo" 域对象标识符。咱们添加一个ACE,而后名叫"Samantha"能"administer"的对象。代码片断相对明显,除了insertAce方法。insertAce方法的第一个参数是肯定在什么位置Acl新条目将被插入。在上面的示例中,咱们只是把新的现有ACE。最后一个参数是一个布尔值指示是否容许或拒绝。大部分时间它将授予(真实的),但若是是否定(假),其实是被屏蔽的权限.

Spring Security并不提供任何特殊的集成自动建立、更新或删除acl DAO或存储库操做的一部分。相反,您须要编写代码如上图所示为你单独的域对象.值得考虑使用AOP在服务层与服务层自动把ACL信息操做.咱们发现这在过去的一个至关有效的方法.

一旦你使用上述技术将一些ACL信息存储在数据库中,下一步是实际使用ACL信息做为受权决策逻辑的一部分。这里有许多选择。您能够编写本身的AccessDecisionVoterAfterInvocationProvider 分别触发一个方法调用以前或以后。这些课程将使用AclService来检索相关的ACL,而后调用的ACL。i`Acl.isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)决定是否授予或拒绝许可。或者,您能够使用咱们的`AclEntryVoterAclEntryAfterInvocationProvider 或 AclEntryAfterInvocationCollectionFilteringProvider类。全部这些类提供一个declarative-based方法评估ACL信息在运行时,释放你须要编写任何代码。请参阅示例应用程序来学习如何使用这些类。

Pre-Authentication场景

在有些状况下,您但愿使用Spring安全受权,可是用户已经被一些外部系统可靠地验证以前访问应用程序。咱们称这种状况为 "pre-authenticated"场景。例子包括 X.509,Siteminder和身份验证的Java EE容器的应用程序正在运行。当使用pre-authentication,Spring Security

*识别用户的请求

*为用户得到当局

细节将取决于外部身份验证机制。用户可能会被他们的证书信息的X.509,或经过一个HTTP请求头Siteminder的状况。若是依靠容器身份验证,用户将被调用getUserPrincipal() 的方法传入的HTTP请求。在某些状况下,外部机制可能为用户提供角色/权威信息但在其余当局必须得到一个单独的源,如UserDetailsService.

Pre-Authentication框架类

由于大多数pre-authentication机制遵循相同的模式,Spring Security一组类,提供一个内部框架实现pre-authenticated身份验证提供者。这个删除复制和容许添加新的实现结构化的方式,无需写一切从头开始。你不须要知道这些类,若是但愿使用相似于X.509 authentication,由于它已经有了一个名称空间配置选项,简单的使用和开始使用。若是你须要使用显式的bean配置或计划编写本身的实现提供的实现如何工做的理解将是有用的。你会发现类“org.springframework.security.web.authentication.preauth”。咱们在适当的地方提供一个大纲你应该咨询Javadoc和源.

抽象的预认证处理过滤器

这个类将检查的当前内容安全上下文,若是空,它将尝试从HTTP请求中提取用户信息并提交AuthenticationManager,子类覆盖如下方法来得到这些信息:

protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);

protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);

把这些后,过滤器将包含返回的数据建立一个PreAuthenticatedAuthenticationToken并提交身份验证。由"authentication",咱们或许真的只是意味着进一步的处理负荷用户的部门,而不是按照标准的Spring Security验证架构。

像其余Spring安全身份验证过滤器,pre-authentication过滤器有一个authenticationDetailsSource属性,默认状况下将建立一个WebAuthenticationDetails 对象来存储更多的信息,好比会话标识符和原始IP地址在 Authentication 对象的属性details。在这种状况下,用户角色信息可从pre-authentication获取机制,数据也存储在这个属性,实现GrantedAuthoritiesContainer接口的细节。这使的身份验证提供者阅读部门外部分配给用户。接下来咱们将看一个具体的例子.

基于J2ee的前验证Web身份验证源细节

若是过滤器配置了一个authenticationDetailsSource这类的一个实例,权威的信息是经过调用isUserInRole(String role)的一组预先肯定的方法为每个"mappable roles"配置的类这些来自一个MappableAttributesRetriever.可能的实现包括硬编码应用程序上下文中的一个列表和阅读的角色信息<security-role>web.xml文件.pre-authentication示例应用程序使用了后一种方法.

有一个额外的阶段(或属性)的角色被映射到Spring Security GrantedAuthority对象使用一个配置Attributes2GrantedAuthoritiesMapper。默认只会添加一般具有ROLE_前缀的名字,但它让你彻底控制行为

前验证身份验证提供者

re-authenticated提供者有更多比为用户负载的UserDetails对象。它经过委托给一个AuthenticationUserDetailsService.后者是相似于标准UserDetailsService但以一个 Authentication对象而不是用户名:

public interface AuthenticationUserDetailsService {
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
}

这个接口可能也其余用途,但pre-authentication它容许访问官方包装在“身份验证”对象,正如咱们在前一节中看到的。PreAuthenticatedGrantedAuthoritiesUserDetailsService这类,或者,它可能表明一个标准的UserDetailsService 经过UserDetailsByNameServiceWrapper 实现.

Http403禁止入口点

AuthenticationEntryPoint是讨论的technical overview 一章。一般它负责启动未通过身份验证的用户的身份验证过程(当他们试图访问受保护的资源),可是在pre-authenticated状况下不适用。你只会配置 ExceptionTranslationFilter与这个类的一个实例,若是你不使用pre-authentication结合其余身份验证机制。它将被称为AbstractPreAuthenticatedProcessingFilter若是用户被拒绝的结果在一个空的身份验证。它老是返回一个“403”错误.

具体实现

X.509认证被 own chapter覆盖.下面咱们来看看一些类,它们提供支持其余pre-authenticated场景.

请求头身份验证(Siteminder)

设置特定的HTTP请求。一个众所周知的例子是Siteminder,经过用户名在一个标题叫SM_USER 。这种机制是类 RequestHeaderAuthenticationFilter支持,只是从标题中提取用户名。它默认使用的名称SM_USER 做为标题名称。看到更多的细节的Javadoc.

注意,当使用这样的一个系统,框架执行任何身份验证检查和extremely重要外部系统的正确配置和保护全部访问应用程序。若是攻击者可以伪造原始请求的头文件没有被发现以后,他们能够选择任何他们但愿的用户名.

Siteminder示例配置

一个典型的配置使用这个过滤器看起来像这样:

<security:http>
<!-- Additional http configuration omitted -->
<security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
</security:http>

<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>

<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
	<bean id="userDetailsServiceWrapper"
		class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
	<property name="userDetailsService" ref="userDetailsService"/>
	</bean>
</property>
</bean>

<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>

咱们认为这里security namespace是用于配置。还假定您已经添加了一个UserDetailsService(称为"userDetailsService")到您的配置加载用户的角色.

Java EE容器认证

J2eePreAuthenticatedProcessingFilter将从 userPrincipal属性中提取 HttpServletRequest.使用这个过滤器一般会结合使用Java EE角色如上所述在< < j2ee-preauth-details > >表示.

有一个示例应用程序代码中使用这种方法,从github获得的代码从github,若是你对这些文件感兴趣你能够看下,代码是在samples/xml/preauth目录中.

LDAP 身份验证

概述

LDAP做为一个中央存储库对用户信息和身份验证服务是经常使用的组织.它也能够用于存储应用程序用户的角色信息.这里有一些不一样的场景对于如何配置LDAP服务器,所以Spring Security LDAP提供者是彻底可配置的,它使用单独的策略为身份验证和角色接口检索,并提供默认的实现,能够配置为处理各类状况.在使用以前你应该熟悉Spring Security LDAP.如下连接提供了一个很好的介绍涉及的概念和使用OpenLDAP免费的LDAP服务器创建一个目录指南http://www.zytrax.com/books/ldap/[http://www.zytrax.com/books/ldap/]. 一些熟悉的JNDI api用于访问LDAP从Java也多是有用的。咱们在LDAP不使用任何第三方LDAP库(Mozilla,JLDAP等等),但Spring 的普遍使用是由LDAP,若是你打算添加您本身的定制,对这方面有所了解对你的项目多是有用的.

使用LDAP身份验证时,重要的是要确保你正确配置LDAP链接池。若是你不熟悉如何作到这一点,你能够参考 Java LDAP documentation.

使用LDAP Spring Security

在Spring的LDAP身份验证安全大体能够分为如下几个阶段

  • 得到独特的LDAP"Distinguished Name",或DN,登陆名。这一般意味着执行搜索的目录,除非用户名的具体映射DNs是提早知道。因此用户可能输入名称登陆"joe",但实际LDAP名称用于验证将完整的DN,如uid=joe,ou=users,dc=spring,dc=io.

  • 验证用户,经过"binding",用户操做的用户的密码与密码属性执行远程"compare" 目录条目的DN.

  • 加载当局为用户的列表.

惟一的例外是当LDAP目录只是被用于检索用户信息并在本地对其进行身份验证.这个不可能设置有限的读访问属性目录,如用户密码.

下面,咱们将看看一些配置场景。完整的可用配置选项的信息,请查阅安全模式名称空间(信息应该在XML编辑器中可用).

配置LDAP服务器

你须要作的第一件事是配置的服务器身份验证应该发生。这是经过使用 <ldap-server> 的元素从安全名称空间。这能够配置为指向外部LDAP服务器,使用的url属性:

<ldap-server url="ldap://springframework.org:389/dc=springframework,dc=org" />

Using an Embedded Test Server

<ldap-server> 元素也能够用来建立一个嵌入式服务器,它能够是很是有用的进行测试和演示。在这种状况下,你没有使用它的url属性:

<ldap-server root="dc=springframework,dc=org"/>

这里咱们指定目录是"dc=springframework,dc=org",这是默认的.这种方式,使用名称空间解析器将建立一个嵌入式Apache目录服务器的类路径和扫描任何LDIF文件,它将尝试加载到服务器。你能够定制这种行为使用ldif的属性,它定义了一个ldif资源加载:

<ldap-server ldif="classpath:users.ldif" />

这使它更容易与LDAP同步,由于它能够方便工做与外部服务器。它还将用户从复杂bean配置须要隔离一个Apache链接目录服务器。使用普通的Spring bean配置将会更加混乱。你必需要有必要的Apache Directory依赖性jar用于您的应用程序使用。如LDAP示例应用程序。

使用绑定验证

这是最多见的LDAP身份验证场景.

<ldap-authentication-provider user-dn-pattern="uid={0},ou=people"/>

这个简单的例子将得到用户的DN替代模式和提供的用户登陆名试图绑定,用户的登陆密码。若是你全部的用户都是存储在单个节点的目录下这很好,若是您但愿配置LDAP搜索筛选器来定位用户,你能够使用如下

<ldap-authentication-provider user-search-filter="(uid={0})"
	user-search-base="ou=people"/>

若是使用上面的服务器定义,这将执行搜索在DN ou=people,dc=springframework,dc=org使用user-search-filter 属性的值做为一个过滤器。用户登陆名是代替过滤器的参数名称,因此它将搜索条目uid属性等于用户名。若是user-search-base并不提供,从根搜索.

加载机构

当局是如何从组加载在LDAP目录中由如下属性控制

  • group-search-base.定义了目录树下的一部分应该执行哪一组搜索。

  • group-role-attribute.属性包含的名称定义的权限组条目。默认为cn

  • 组搜索过滤器。过滤器用于搜索组成员。默认是 uniqueMember={0},对应于groupOfUniqueNames的LDAP类脚注:(注意,这是不一样于缺省配置底层DefaultLdapAuthoritiesPopulator使用member={0}。]。在这种状况下,替换参数是用户的专有名称。能够使用参数{1}若是你想过滤的登陆名.

所以,若是咱们使用如下配置

<ldap-authentication-provider user-dn-pattern="uid={0},ou=people"
		group-search-base="ou=groups" />

和通过验证的成功做为用户"ben",随后的加载下当局将执行搜索的目录条目的ou=groups,dc=springframework,dc=org,寻找条目包含的属性uniqueMember价值uid=ben,ou=people,dc=springframework,dc=org。默认的权限名称前缀ROLE_ 前缀。你能够改变这个使用 role-prefix属性。若是你不想要任何前缀,使用role-prefix="none".加载机构的更多信息,请参阅DefaultLdapAuthoritiesPopulator类的Javadoc.

实现类

上面的名称空间配置选项咱们使用易于使用,更比使用Spring bean简洁明确。有些状况下,您可能须要了解如何配置Spring Security LDAP直接在您的应用程序上下文。您可能但愿定制的一些类的行为,例如。若是你使用名称空间配置,那么你能够跳过这一节和下一个.

LDAP provider,LdapAuthenticationProvider,实际上并不作太多工做自己,而是表明其余两个bean,一个LdapAuthenticator 和一个LdapAuthoritiesPopulator分别负责验证用户和检索用户的组GrantedAuthority.

Ldap身份验证明现

authenticator还负责检索所需的用户属性。这是由于权限的属性可能取决于正在使用的身份验证类型。例如,若是绑定用户,与用户可能须要阅读的权限有关.

目前有两种身份验证策略提供Spring安全:

*直接向LDAP服务器的身份验证("bind" 身份验证)。

*密码比较,用户提供的密码是与一个存储在存储库中。这能够经过检索密码属性的值和检查本地或经过执行LDAP"compare"操做,提供的密码在哪里传递到服务器进行比较和真正的密码值是没有检索到.

经常使用功能

以前能够验证一个用户(经过策略),专有名称(DN)必须从登陆名得到提供给应用程序.这能够经过简单的模式匹配(经过设置setUserDnPatterns数组属性)或经过设置userSearch属性.对于DN模式匹配方法,格式是使用一个标准的Java模式,将登陆名代替参数{0}.他应该相对于DN模式,配置SpringSecurityContextSource 将绑定到部分(参见connecting to the LDAP server 更多这方面的信息).ldap://monkeymachine.co.uk/dc=springframework,dc=org和有一个模式uid={0},ou=greatapes,"gorilla" 的登陆名将会映射到一个DN`uid=gorilla,ou=greatapes,dc=springframework,dc=org`. 每一个配置的DN模式将尝试直到找到一个匹配,有关使用搜索的信息,看到部分下面的search objects,结合这两种方法也能够使用——模式首先会检查,若是没有找到匹配DN,将使用搜索.

绑定认证者

org.springframework.security.ldap BindAuthenticator实现身份验证绑定验证策略。它只是试图将用户绑定.

身份验证密码比较

PasswordComparisonAuthenticator实现了密码比较验证策略.

链接到LDAP服务器

上面讨论的bean必须可以链接到服务器。他们都必须提供一个SpringSecurityContextSource这是SpringLDAP的ContextSource的延伸。除非你有特殊要求,您一般会配置一个DefaultSpringSecurityContextSource bean,能够配置LDAP服务器的URL和可选的"manager"的用户的用户名和密码,使用时将默认绑定到服务器(而不是匿名绑定)。更多信息,读取这个类的Javadoc和SpringLDAP的AbstractContextSource”.

LDAP搜索对象

一般须要一个比DN-matching定位目录中的用户条目更复杂的策略,这能够封装在一个LdapUserSearch实例,能够提供身份验证明现.例如,让他们来定位用户.提供的实现是FilterBasedLdapUserSearch.

滤波器基于Ldap用户搜索

这个bean使用LDAP目录中的过滤器匹配用户对象。Javadoc的过程解释相应的搜索方法 JDK DirContext class.做为解释,搜索筛选器能够提供参数。这个类,惟一有效的参数是{0}将取代用户的登陆名.

Ldap当局填充器

验证用户成功后,LdapAuthenticationProvider 将试图经过调用配置LdapAuthoritiesPopulator bean加载一组当局用户.DefaultLdapAuthoritiesPopulator 是一个实现加载当局经过搜索目录组的用户成员(一般这些将groupOfNames”或groupOfUniqueNames加入目录中的条目)详细内容,请参阅这个类的Javadoc中它是如何工做的.

若是你只想使用LDAP身份验证,但加载当局从不一样来源(好比数据库),那么您能够提供本身的实现这个接口和注入.

Spring Bean 配置

典型的配置中,咱们这里讨论使用一些bean,看起来像这样:

<bean id="contextSource"
		class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://monkeymachine:389/dc=springframework,dc=org"/>
<property name="userDn" value="cn=manager,dc=springframework,dc=org"/>
<property name="password" value="password"/>
</bean>

<bean id="ldapAuthProvider"
	class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
	<constructor-arg ref="contextSource"/>
	<property name="userDnPatterns">
	<list><value>uid={0},ou=people</value></list>
	</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean
	class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
	<constructor-arg ref="contextSource"/>
	<constructor-arg value="ou=groups"/>
	<property name="groupRoleAttribute" value="ou"/>
</bean>
</constructor-arg>
</bean>

这将设置提供程序访问LDAP服务器URL`ldap://monkeymachine:389/dc=springframework,dc=org`.身份验证将由试图结合DN`uid=<user-login-name>,ou=people,dc=springframework,dc=org`.成功的身份验证以后,角色分配给用户经过搜索下的DN`ou=groups,dc=springframework,dc=org`用默认的过滤器(member=<user’s-DN>).角色名称将从每个"ou"属性开始匹配.

配置一个用户搜索对象,使用过滤器(uid=<user-login-name>) 的使用而不是DN-pattern(或补充),您将配置如下bean

<bean id="userSearch"
	class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value="(uid={0})"/>
<constructor-arg index="2" ref="contextSource" />
</bean>

并使用它经过设置BindAuthenticator bean的 userSearch属性.authenticator将调用搜索对象来得到正确的用户做为该用户的DN以前绑定.

LDAP Attributes and Customized UserDetails

身份验证使用LdapAuthenticationProvider 的最终结果是同样的一个正常的Spring安全身份验证使用标准的UserDetailsService界面。建立一个UserDetails”对象并返回存储在Authentication”对象。做为UserDetailsService使用,一个常见需求是可以定制这个实现和添加额外的属性。当使用LDAP,这些一般会从用户条目属性。UserDetails对象的建立是由提供者的UserDetailsContextMapper策略,负责从LDAP上下文映射用户对象和数据:

public interface UserDetailsContextMapper {

UserDetails mapUserFromContext(DirContextOperations ctx, String username,
		Collection<GrantedAuthority> authorities);

void mapUserToContext(UserDetails user, DirContextAdapter ctx);
}

惟一重要的是第一个方法进行身份验证。若是您提供该接口的一个实现,它注入LdapAuthenticationProvider,你可以控制如何建立UserDetails对象。Spring 的第一个参数是一个实例LDAP的DirContextOperations可让你接触的LDAP属性加载在身份验证。 username参数是用于验证和最后一个参数是集当局为用户加载的配置 LdapAuthoritiesPopulator.

上下文数据加载略有不一样的方式取决于您正在使用的身份验证类型。 BindAuthenticator,返回的上下文绑定操做将被用于读取属性,不然数据将从配置读取使用标准的背景下得到ContextSource(当配置搜索来定位用户,这将是搜索返回的数据对象).

活动目录的认证

活动目录支持本身的标准身份验证选项,和正常的使用模式不适合太明显与标准LdapAuthenticationProvider.一般执行身份验证使用域用户名(user@domain),而不是使用LDAP专有名称.为了更简单,Spring Security 3.1有一个身份验证提供者是一个典型的定制活动目录设置.

Active Directory Ldap身份验证提供者

配置ActiveDirectoryLdapAuthenticationProvider很是简单。你只须要提供域名和LDAP服务器的URL提供地址脚注:[还能够得到使用DNS查找服务器的IP地址。当前不支持,可是但愿在之后的版本能够实现)。一个例子配置会看起来像这样:

<bean id="adAuthenticationProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
	<constructor-arg value="mydomain.com" />
	<constructor-arg value="ldap://adserver.mydomain.com/" />
</bean>
}

注意,不须要指定一个单独的ContextSource来定义服务器位置- bean是彻底自包含的。用户名为sharon,例如,将可以验证经过输入用户名sharon或完整的Active Directory`userPrincipalName`,即 sharon@mydomain.com.用户的目录条目将被定位,并可能返回的属性中使用自定义建立的UserDetails对象(UserDetailsContextMapper能够被注入为此,如上所述)。全部与目录发生交互用户的身份。没有一个"manager"用户的概念.

默认状况下,用户当局正在从memberOf 得到用户输入的属性值。政府再分配给用户能够使用被定制UserDetailsContextMapper。你也能够注入一个GrantedAuthoritiesMapper提供者实例来控制政府最终在 Authentication对象.

活动目录错误代码

默认状况下,一个失败的结果将致使一个标准的Spring Security`BadCredentialsException`,若是你设置的属性convertSubErrorCodesToExceptions 是true, 异常消息将解析试图提取活性Directory-specific错误代码,提升一个更具体的异常。检查类Javadoc的更多信息。

JSP 标签库

Spring Security有本身的标签库提供基本支持访问安全信息并在jsp应用安全约束.

宣布Taglib

要使用的任何标签,必须有安全JSP 标签库:

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

受权标签

这个标签是用来肯定是否应评估其内容。在Spring Security 3.0中,能够以两种方式使用脚注:[遗留的选项从Spring Security 2.0也支持,但不推荐.].第一种方法使用一个web-security expression,access 属性中指定的标签,表达式求值将委托给SecurityExpressionHandler<FilterInvocation> 中定义的应用程序(你应该启用web表达式<http>的名称空间配置,以确保这个服务是可用的).

<sec:authorize access="hasRole('supervisor')">

此内容将只对用户可见的"supervisor"权威的< tt > GrantedAuthority < / tt >。

</sec:authorize>

在与Spring Security PermissionEvaluator共同使用时,标签也能够用来检查权限.例如:

<sec:authorize access="hasPermission(#domain,'read') or hasPermission(#domain,'write')">

做为一个请求属性命名的"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请求,并调用安全拦截器请求是否会成功或失败,这容许您表明您定义的访问控制设置中使用intercept-url声明<http>的名称空间配置省去了重复的信息(如所需的角色)在您的jsp.这种方法还能够加上一个method属性,提供HTTP方法,更具体的匹配.

布尔结果评估标签(是否容许或拒绝访问)经过设置var属性变量名称能够存储在一个页面上下文范围变量,避免复制和从新评估在页面中的其余点.

禁用标记受权进行测试

隐藏连接在页面不防止未经受权的用户访问URL。他们能够直接在浏览器中类型,例如,做为您的测试过程的一部分,您可能想要显示隐藏领域为了检查环节是安全的后端。若是你设置系统属性 spring.security.disableUISecurity 为 true,authorize的标签仍然会跑但不会隐藏其内容,默认状况下它也会包含<span class="securityHiddenUI">…​</span> 标签。这容许你显示"hidden"与一个特定的CSS样式等内容不一样的背景颜色。尝试运行此属性启用的"tutorial"示例应用程序,例如.

你也能够设置spring.security.securedUIPrefixspring.security.securedUISuffix属性,若是你想改变周围的文字从默认的跨度标签(或使用空字符串彻底删除).若是你想改变周围文本从默认“跨度”标签(或使用空字符串彻底删除它).

身份验证标记

这个标签容许访问当前存储在安全内 Authentication对象,它直接在JSP中 呈现一个属性对象.因此,例如,若是principal`属性的Authentication是Spring Security的UserDetails的对象的一个实例,以后用<sec:authentication property="principal.username" /> 将会显示当前用户的名称.

固然,这种事情没有必要使用JSP标记,有些人喜欢保持尽量少的逻辑视图.您能够在你的MVC控制器访问Authentication对象(经过调用SecurityContextHolder.getContext().getAuthentication())并将数据直接添加到您的模型渲染的视图.

The accesscontrollist Tag

这个标记只在使用Spring Security的ACL模块,它检查一个以逗号分隔的所需权限指定的域对象.若是当前用户全部的权限,而后标记的内容将被评估。若是他们不这样作,它将被忽略.例如

<sec:accesscontrollist hasPermission="1,2" domainObject="${someObject}">

这将显示用户在给定对象上的全部权限所表明的值“1”或“2”.

</sec:accesscontrollist>

在程序内容中,权限被传递到“PermissionFactory”中定义中定义,将它们转换为ACL`Permission`的实例,因此他们支持任何格式工厂,他们不必定是整数,字符串能够像READWRITE.若是没有找到PermissionFactory ,将使用DefaultPermissionFactory的一个实例.程序中的“AclService”将被用于加载Acl的实例提供对象.Acl的将调用所需的权限,以检查是否都是合法的.

这个标签还支持var属性,以一样的方式authorize 的标签.

csrfInput标签

若是启用了CSRF保护,这个标签插入一个隐藏表单字段的正确名称和值CSRF保护令牌。若是没有启用CSRF保护,这个标签输出.对于任何的<form:form> 标签使用,一般Spring Security自动插入一个CSRF表单字段.但若是因为某种缘由你不能使用<form:form>,你能够使用<form:form>更换.

你应该把这个标签在一个HTML <form></form>形式的块,一般地方其余输入字段.不要将这个标签放置在一个Spring <form:form></form:form>,block—Spring Security会自动处理 Spring.

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

csrfMetaTags标签

若是启用了CSRF保护,这个标签插入元素标记包含CSRF保护令牌表单字段和标题名称和CSRF保护令牌的值。这些元素标记可用于使用CSRF保护在JavaScript应用程序.

你应该把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", "http://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", "http://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: "http://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: "http://www.example.org/do/something",
				type: "POST",
				headers: headers,
				...
			});

		<script>
	</head>
	<body>
		...
	</body>
</html>

若是不启用CSRF保护,csrfMetaTags输出.

Java Authentication and Authorization Service (JAAS) Provider

概述

Spring Security提供一个包能够将身份验证请求委托给Java身份验证和受权服务(JAAS).这个包是在下面详细讨论.

Jaas远程准入Provider摘要

AbstractJaasAuthenticationProvider提供JAAS AuthenticationProvider实现的基础.子类必须实现方法,建立了LoginContextAbstractJaasAuthenticationProvider有许多依赖关系,下面讨论它

JAAS回调处理程序

大多数JAAS LoginModule的年代须要一个回调。这些回调一般用于得到用户的用户名和密码.

在Spring Security部署中,Spring Security负责这个用户交互(经过身份验证机制),所以,当委托到JAAS身份验证请求,Spring安全的身份验证机制已经彻底填充一个身份验证的对象包含全部所需的JAAS LoginModule的信息.

所以,为Spring Security JAAS包提供了两个默认回调处理程序,JaasNameCallbackHandlerJaasPasswordCallbackHandler.每个回调处理程序实现JaasAuthenticationCallbackHandler.在大多数状况下,这些回调处理程序能够简单地使用不了解内部力学.

对于那些须要彻底控制回调行为,内部AbstractJaasAuthenticationProviderInternalCallbackHandler 包装这些JaasAuthenticationCallbackHandler.InternalCallbackHandler是类实现JAAS正常的CallbackHandler接口。任什么时候候使用JAAS LoginModule的,它是经过一个应用程序上下文列表配置InternalCallbackHandler年代。若是LoginModule的请求一个回调兑InternalCallbackHandler,回调是循序传递到JaasAuthenticationCallbackHandler被包装.

JAAS受权授与者

JAAS和主程序一块儿工做。甚至"roles"在JAAS表示为主体,Spring Security, 另外一方面, 与Authentication对象,每一个Authentication对象包含一个校长,和多个GrantedAuthority .促进这些不一样概念之间的映射,Spring Security的JAAS包包括一个AuthorityGranter接口.

AuthorityGranter 负责检查JAAS并返回一组字符串的,表明权利分配给主程序.对于每个权威返回字符串.为每一个字符串,返回权威AbstractJaasAuthenticationProvider建立了一个“JaasGrantedAuthority”(实现Spring Security的GrantedAuthority 接口)包含字符串和JAAS程序AuthorityGranter经过.AbstractJaasAuthenticationProvider得到JAAS,首先成功地验证用户的使用JAAS LoginModule的凭证,而后访问LoginContext将它返回.调用LoginContext.getSubject().getPrincipals(),与每一个生成的AuthorityGranter主要传递给每一个定义为与AbstractJaasAuthenticationProvider.setAuthorityGranters(List)的内容.

Spring Security不包括任何生产AuthorityGranter,每个JAAS都有一个特定实现的意义。然而,有一个TestAuthorityGranter的单元测试演示了一个简单的AuthorityGranter实现.

默认Jaas身份验证提供

DefaultJaasAuthenticationProvider容许将一个JAAS配置的对象注入依赖项。而后使用JAAS配置的注入建立一个LoginContext.这意味着DefaultJaasAuthenticationProvider不绑定任何特定实现的Configuration由于JaasAuthenticationProvider.

在内存配置

为了使Configuration容易注入一个DefaultJaasAuthenticationProvider, 默认在内存中实现名为“InMemoryConfiguration”.实现构造函数接受一个Map,每一个键表明登陆配置名称和值表明一个数组AppConfigurationEntry 。若是没有找到Map映射提供了InMemoryConfiguration还支持一个默认的AppConfigurationEntry对象Array,使用详情,请参阅“InMemoryConfiguration”的类级别的javadoc.

默认的Jaas身份验证提供者配置示例

而 InMemoryConfiguration的Spring能够更详细配置standarad JAAS配置文件.它在文中 DefaultJaasAuthenticationProviderJaasAuthenticationProvider 更灵活,由于它不依赖默认配置的实现.

使用InMemoryConfiguration配置一个例子DefaultJaasAuthenticationProvider .注意,自定义的“配置”能够很容易地实现注入DefaultJaasAuthenticationProvider .

<bean id="jaasAuthProvider"
class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
<property name="configuration">
<bean class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
<constructor-arg>
	<map>
	<!--
	SPRINGSECURITY is the default loginContextName
	for AbstractJaasAuthenticationProvider
	-->
	<entry key="SPRINGSECURITY">
	<array>
	<bean class="javax.security.auth.login.AppConfigurationEntry">
		<constructor-arg value="sample.SampleLoginModule" />
		<constructor-arg>
		<util:constant static-field=
			"javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED"/>
		</constructor-arg>
		<constructor-arg>
		<map></map>
		</constructor-arg>
		</bean>
	</array>
	</entry>
	</map>
	</constructor-arg>
</bean>
</property>
<property name="authorityGranters">
<list>
	<!-- You will need to write your own implementation of AuthorityGranter -->
	<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
</list>
</property>
</bean>

Jaas Provider准入

JaasAuthenticationProvider 假定默认的Configuration的一个实例http://download.oracle.com/javase/1.4.2/docs/guide/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html[ ConfigFile].这种假设是为了尝试更新Configuration.JaasAuthenticationProvider使用默认配置的建立LoginContext.

假设咱们有一个JAAS登陆配置文件,/WEB-INF/login.conf, 用下面的内容:

JAASTest {
	sample.SampleLoginModule required;
};

像全部Spring Security beans,JaasAuthenticationProvider经过应用程序上下文配置.下面的定义将对应于上面的JAAS登陆配置文件

<bean id="jaasAuthenticationProvider"
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="/WEB-INF/login.conf"/>
<property name="loginContextName" value="JAASTest"/>
<property name="callbackHandlers">
<list>
<bean
	class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler"/>
<bean
	class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler"/>
</list>
</property>
<property name="authorityGranters">
	<list>
	<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
	</list>
</property>
</bean>

项目运行

若是配置,“JaasApiIntegrationFilter”将试图运行“JaasAuthenticationToken”上的Subject。这意味着能够使用访问Subject:

Subject subject = Subject.getSubject(AccessController.getContext());

这种集成能够很容易地使用jaas-api-provision配置属性。当集成遗留或外部依赖JAAS Subject API被填充,这个特性颇有用

CAS 身份验证

Overview

JA-SIG产生一个企业范围的单点登陆系统称为CAS。与其余计划,JA-SIG中央身份验证服务是开源的,普遍使用,容易理解,平台独立,支持代理功能。Spring Security彻底支持ca,并提供了一个简单的迁移路径从Spring Security的单个应用程序部署到多个应用程序部署的企业级CAS服务器.

CAS如何工做

而中科院网站包含文档的细节CAS的体系结构,提出整体概述了Spring Security.Spring Security 3.x支持中科院。在撰写本文时,还在使用CAS服务器3.4版.

在您的企业,您须要设置一个CAS服务器。CAS服务器只是一个标准的WAR文件,因此设置您的服务器没有什么困难。在WAR文件您将定制登陆和其余单点登陆页面显示给用户.

当部署一个CAS 3.4服务器,您还须要指定一个AuthenticationHandlerdeployerConfigContext.xml包含ca。AuthenticationHandler有一个简单的方法,该方法返回一个布尔判断是否一个给定的证书是有效的.你AuthenticationHandler的实现须要连接到某种类型的后端身份验证存储库,如LDAP服务器或数据库,CAS自己包含许多AuthenticationHandler的协助.当你下载服务器和部署war文件时,它被设置为成功进行身份验证的用户输入一个密码匹配他们的用户名,用于测试.

Spring Security和CAS交互序列

基本的web浏览器之间的交互,CAS服务器和春天Security-secured服务以下:

  • web用户浏览服务的公共页面.CAS或Spring Security不参与。

  • 最终用户请求一个页面或者安全bean的使用是安全的。Spring Security的ExceptionTranslationFilter将检测到AccessDeniedExceptionAuthenticationException.

  • 由于用户的Authentication的对象(或缺少)引发了AuthenticationException,ExceptionTranslationFilter将调用配置的AuthenticationEntryPoint。若是使用CAS,这将是CasAuthenticationEntryPoint 类.

  • CasAuthenticationEntryPoint会将用户的浏览器重定向到CAS服务器。它也将显示一个service 参数,这是春天的回调URL安全服务(应用程序)。例如,浏览器的URL重定向多是https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas。

  • 用户的浏览器重定向到ca后,他们将提示输入用户名和密码。若是用户提供了一个会话cookie这代表他们以前登陆的,他们不会被提示从新登陆(这个过程有一个例外,咱们稍后将讨论)。中科院将使用PasswordHandler(或果使用CAS 3.0`AuthenticationHandler`)以上讨论决定是否用户名和密码是有效的。

  • 成功登陆以后,中科院重定向用户的浏览器将回到原来的服务。它还将包括一个ticket参数,这是一个不透明的字符串表明"service ticket".继续咱们前面的例子中,浏览器重定向到URL https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ。

  • 服务的web应用程序中,CasAuthenticationFilter老是侦听请求/login/cas(这是可配置的,可是咱们将使用默认本介绍)。处理过滤器将构造一个UsernamePasswordAuthenticationToken表明服务票证。校长就等于CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER,同时将服务票证凭据不透明值。这种身份验证请求将被交给AuthenticationManager配置。

  • AuthenticationManager实现ProviderManager,这是依次配置了 CasAuthenticationProviderCasAuthenticationProvider只响应包含UsernamePasswordAuthenticationToken(如CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER)和CasAuthenticationToken (稍后讨论).

  • CasAuthenticationProvider将验证服务票据使用TicketValidator实现。这一般是一个Cas20ServiceTicketValidator这是一个类包含在CAS客户端库。若是应用程序须要验证代理机票,使用 Cas20ProxyTicketValidator .TicketValidator 发出一个HTTPS请求CAS服务器以验证服务票证。它可能还包括一个代理回调URL,包括在这个例子:https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https / /server3.company.com/webapp/login/cas/proxyreceptor。

  • CAS服务器,验证请求将被接收。若是提供的服务票证匹配服务URL票发行,中科院将提供积极响应XML显示用户名。若是任何代理参与身份验证(下面讨论),代理列表中也包含在XML响应。

  • [OPTIONAL] 若是请求CAS验证服务包括代理回调URL(在pgtUrl 参数),中科院将包括一个 pgtIou字符串在XML响应。这种pgtIou表明一个借据proxy-granting机票。CAS服务器会建立本身的HTTPS链接回pgtUrl.这是相互CAS服务器进行身份验证,声称服务URL。HTTPS链接将被用来发送一个代理发放门票最初的web应用程序.例如,https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH。

  • Cas20TicketValidator将收到CAS服务器解析XML。它将返回到CasAuthenticationProviderTicketResponse,其中包括用户名(强制),代理列表(若是有涉及),和proxy-granting票借据(若是请求代理回调)。

  • 接下来的CasAuthenticationProvider将称之为CasProxyDecider配置. CasProxyDecider代表代理列表中 TicketResponse是否接受服务。几个实现提供SpringSecurity:`RejectProxyTickets`,AcceptAnyCasProxy和 NamedCasProxyDecider。这些名字在很大程度上是自解释的,除了 NamedCasProxyDecider容许List 提供可信的代理。

  • CasAuthenticationProvider将下一个请求的AuthenticationUserDetailsService加载GrantedAuthority 对象,适用于用户包含在 Assertion.

  • 若是没有问题,CasAuthenticationProvider构造CasAuthenticationToken包括细节包含在TicketResponseGrantedAuthority.

  • 控制而后返回CasAuthenticationFilter,把CasAuthenticationToken建立安全上下文.

  • AuthenticationException致使用户的浏览器被重定向到原始页面 (or a custom destination根据配置).

很好,你还在这里!如今让咱们看看这是如何配置的

配置客户案件

因为Spring Security中科院的web应用程序是很容易.这是假设你已经知道使用Spring安全的基本知识,下面这些是不会再覆盖。咱们假设基于命名空间的配置使用,根据须要添加在CAS bean。每一个部分创建在前一节。一个完整的CAS sample application能够在Spring Security样本找到.

门票远程准入服务

本节描述如何设置Spring Security验证Service Tickets。不少时候这都是一个web应用程序须要。您须要添加一个“ServiceProperties”bean到您的应用程序上下文。这表明你的CAS服务:

<bean id="serviceProperties"
	class="org.springframework.security.cas.ServiceProperties">
<property name="service"
	value="https://localhost:8443/cas-sample/login/cas"/>
<property name="sendRenew" value="false"/>
</bean>

service必须等于一个URL,将由CasAuthenticationFilter监控.sendRenew的默认值为false,但若是应用程序尤为敏感应该设置为true.这个参数的做用是告诉CAS登陆服务,一个单点登陆登陆是不可接受的。相反,用户将须要从新输入本身的用户名和密码来访问服务.

下面的bean应该配置开始CAS认证过程(假设您正在使用一个名称空间配置):

<security:http entry-point-ref="casEntryPoint">
...
<security:custom-filter position="CAS_FILTER" ref="casFilter" />
</security:http>

<bean id="casFilter"
	class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>

<bean id="casEntryPoint"
	class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>

CAS操做,ExceptionTranslationFilter必须有它authenticationEntryPoint属性设置为CasAuthenticationEntryPoint”bean.这能够很容易地经过使用 entry-point-ref,是在上面的示例中完成的。CasAuthenticationEntryPoint必须参考的ServiceProperties bean(如上所述),它提供了企业的CAS登陆服务器的URL.就是用户的浏览器重定向.

CasAuthenticationFilter 已经和属性UsernamePasswordAuthenticationFilter 很是类似(用于基于表单的登陆)。您能够使用这些属性来定制诸如认证成功和失败的行为.

接下来,您须要添加一个“CasAuthenticationProvider”及其合做者:

<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager>

<bean id="casAuthenticationProvider"
	class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
	<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
	<constructor-arg ref="userService" />
	</bean>
</property>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
	<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
	<constructor-arg index="0" value="https://localhost:9443/cas" />
	</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>

<security:user-service id="userService">
<security:user name="joe" password="joe" authorities="ROLE_USER" />
...
</security:user-service>

CasAuthenticationProvider 使用UserDetailsService实例加载权限用户,一旦被CAS认证。咱们已经演示了一个简单的内存设置。注意,CasAuthenticationProvider 并不实际使用密码进行身份验证,但它使用当局.

若是你参考How CAS Works 部分beans 是合理的.

这对CAS完成最基本的配置。若是你没有作任何错误,您的web应用程序框架内应该记录地工做CAS的单点登陆。没Spring Security 的其余部分的安全须要关心事实CAS处理身份验证。在下面几节中咱们将讨论一些更高级的配置(可选).

Single Logout

CAS协议支持单注销和Spring Security 很容易地添加到您的安全配置。下面是更新Spring Security配置处理单注销

<security:http entry-point-ref="casEntryPoint">
...
<security:logout logout-success-url="/cas-logout.jsp"/>
<security:custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
<security:custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
</security:http>

<!-- This filter handles a Single Logout Request from the CAS Server -->
<bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>

<!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
<bean id="requestSingleLogoutFilter"
	class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="https://localhost:9443/cas/logout"/>
<constructor-arg>
	<bean class=
		"org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</constructor-arg>
<property name="filterProcessesUrl" value="/logout/cas"/>
</bean>

logout元素记录用户的本地应用程序,但不与CAS服务器终止会话或任何其余已经登陆的应用程序。requestSingleLogoutFilter的过滤器将容许 /spring_security_cas_logout请求的url重定向应用程序配置的CAS服务器注销url。而后CAS服务器将发送一个注销请求签署的全部服务.singleLogoutFilter处理单注销请求经过在静态Map 查找的HttpSession而后无效.

也许会困惑,为何logout 元素和singleLogoutFilter是必要的。最佳实践是在当地注销以来首次 SingleSignOutFilter只是将HttpSession的存储在一个静态的Map,以调用无效。与上面的配置中,注销的流程是

  • /logout 的用户请求将记录用户的本地应用程序并发送用户注销成功页面。

  • 注销成功页面 /cas-logout.jsp’,为了注销的全部应用程序应该指导用户点击一个连接指向的/logout/cas

  • 当用户单击连接时,用户被重定向到中科院单注销URL(https://localhost:9443/cas/logout).

  • 在CAS服务器端,CAS单注销URL而后提交单注销全部中科院服务的请求。在中科院服务方面,JASIG invaliditing的SingleSignOutFilter处理注销请求的原始会话。

下一步是添加到你的web.xml中

<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>
	org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
	<param-name>encoding</param-name>
	<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>
	org.jasig.cas.client.session.SingleSignOutHttpSessionListener
</listener-class>
</listener>

验证与CAS无状态的服务

本节描述如何使用CAS认证服务。换句话说,本节将讨论如何创建一个客户使用服务,与 CAS进行身份验证。下一节描述了如何设置使用CAS无状态的服务进行身份验证.

配置CAS得到代理发放门票

为了验证一个无状态服务,应用程序须要得到一个代理发放门票(页面表)。本节描述如何配置Spring Security得到页面表构建在thencas-st[Service Ticket Authentication] 配置.

第一步是包括ProxyGrantingTicketStorage在你的Spring Security配置。这是用于存储页面表所得到CasAuthenticationFilter,这样他们能够用来得到代理票。一个示例配置以下所示

<!--
NOTE: In a real application you should not use an in
		memory implementation. You will also want to ensure
		to clean up expired tickets by calling ProxyGrantingTicketStorage.cleanup()
-->
<bean id="pgtStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>

下一步是更新的CasAuthenticationProvider可以得到代理票。将 Cas20ServiceTicketValidator替换为一个Cas20ProxyTicketValidatorproxyCallbackUrl应该设置为一个应用程序将接收页面表的URL.最后,配置也应该参考ProxyGrantingTicketStorage因此它能够使用页面表获取代理机票。你能够找到一个例子,

<bean id="casAuthenticationProvider"
	class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
...
<property name="ticketValidator">
	<bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator">
	<constructor-arg value="https://localhost:9443/cas"/>
		<property name="proxyCallbackUrl"
		value="https://localhost:8443/cas-sample/login/cas/proxyreceptor"/>
	<property name="proxyGrantingTicketStorage" ref="pgtStorage"/>
	</bean>
</property>
</bean>

最后一步是在 ProxyGrantingTicketStorage更新 CasAuthenticationFilter 接受页面表和存储。重要的是proxyReceptorUrlproxyCallbackUrl匹配的Cas20ProxyTicketValidator.一个示例配置以下所示

<bean id="casFilter"
		class="org.springframework.security.cas.web.CasAuthenticationFilter">
	...
	<property name="proxyGrantingTicketStorage" ref="pgtStorage"/>
	<property name="proxyReceptorUrl" value="/login/cas/proxyreceptor"/>
</bean>
使用代理调用无状态服务票

如今Spring Security得到页面表,您能够使用它们来建立代理门票能够用来验证无状态的服务,CAS sample applicationProxyTicketSampleServlet包含一个工做示例。能够找到示例代码以下:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {
// NOTE: The CasAuthenticationToken can also be obtained using
// SecurityContextHolder.getContext().getAuthentication()
final CasAuthenticationToken token = (CasAuthenticationToken) request.getUserPrincipal();
// proxyTicket could be reused to make calls to the CAS service even if the
// target url differs
final String proxyTicket = token.getAssertion().getPrincipal().getProxyTicketFor(targetUrl);

// Make a remote call using the proxy ticket
final String serviceUrl = targetUrl+"?ticket="+URLEncoder.encode(proxyTicket, "UTF-8");
String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8");
...
}

代理身份验证票

CasAuthenticationProvider 的区分有状态的和无状态的客户。一个有状态的客户被认为是提交CasAuthenticationFilterfilterProcessUrl.无状态的客户的任何一个身份验证请求CasAuthenticationFilterfilterProcessUrl另外一个URL更好.

由于远程协议没有办法展现本身的HttpSession,它不可能依赖于默认的作法将安全上下文存储在会话请求之间。此外,因为CAS服务器无效罚单后,在后续请求中验证了TicketValidator呈现相同的代理机票不会工做.

一个显而易见的选择是为远程协议客户不使用CAS。然而,这将消除许多CAS。做为一个中间立场,CasAuthenticationProvider使用StatelessTicketCache.这是仅用于无状态的客户主要使用等于CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER.发生了什么是CasAuthenticationProvider将存储产生的CasAuthenticationToken放在StatelessTicketCache,键控代理机票。所以,远程协议客户能够呈现相同的代理机票和 CasAuthenticationProvider不须要接触CAS服务器进行验证(除了第一个请求)。一旦验证,除了最初的目标服务代理机票能够用于url.

本节创建在前面几节容纳代理机票验证.第一步是指定验证全部工件以下所示

<bean id="serviceProperties"
	class="org.springframework.security.cas.ServiceProperties">
...
<property name="authenticateAllArtifacts" value="true"/>
</bean>

下一步是指定servicePropertiesauthenticationDetailsSourceCasAuthenticationFilter。“serviceProperties”属性指示 CasAuthenticationFilter尝试全部的工件进行身份验证,而不是只有出如今filterProcessUrl.ServiceAuthenticationDetailsSource建立了一个ServiceAuthenticationDetails 确保当前URL,基于HttpServletRequest,用做服务URL时验证票。方法用于生成服务URL能够被注入一个自定义定制的AuthenticationDetailsSource ,返回一个自定义ServiceAuthenticationDetails.

<bean id="casFilter"
	class="org.springframework.security.cas.web.CasAuthenticationFilter">
...
<property name="serviceProperties" ref="serviceProperties"/>
<property name="authenticationDetailsSource">
	<bean class=
	"org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
	<constructor-arg ref="serviceProperties"/>
	</bean>
</property>
</bean>

您还须要更新CasAuthenticationProvider处理代理票。将Cas20ServiceTicketValidator替换为一个Cas20ProxyTicketValidator.您须要配置代理的statelessTicketCache,你想接受。你能够找到一个例子,下面的更新须要接受全部代理.

<bean id="casAuthenticationProvider"
	class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
...
<property name="ticketValidator">
	<bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator">
	<constructor-arg value="https://localhost:9443/cas"/>
	<property name="acceptAnyProxy" value="true"/>
	</bean>
</property>
<property name="statelessTicketCache">
	<bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
	<property name="cache">
		<bean class="net.sf.ehcache.Cache"
			init-method="initialise" destroy-method="dispose">
		<constructor-arg value="casTickets"/>
		<constructor-arg value="50"/>
		<constructor-arg value="true"/>
		<constructor-arg value="false"/>
		<constructor-arg value="3600"/>
		<constructor-arg value="900"/>
		</bean>
	</property>
	</bean>
</property>
</bean>

X.509 Authentication

概述

最经常使用的X.509 证书身份验证是验证服务器在使用SSL的身份,从浏览器一般在使用HTTPS。浏览器会自动检查服务器证书的已发布(即数字签名)的一个受信任的证书颁发机构的列表维护。

您还能够使用SSL与"mutual authentication";服务器将请求从客户端做为一个有效的证书的SSL握手。服务器将验证客户端经过检查其签署的证书是一个可接受的权威。若是提供了一个有效的证书,它能够经过servlet API的应用程序。Spring Security X.509模块提取证书使用一个过滤器。它将证书映射到一个应用程序用户和加载用户的组授予机关使用标准的Spring安全基础设施。

增长X.509认证您的Web应用程序

X.509客户端身份验证很是简单。只是<x509/> 元素添加到您的http安全性名称空间配置.

<http>
...
	<x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/>;
</http>

元素有两个可选属性:

  • subject-principal-regex正则表达式用来提取用户名从证书的主题名称。上面所示的默认值。这是用户名,将传递给“UserDetailsService”为用户负载当局。

  • user-service-ref.这是的bean Id`UserDetailsService`用于x.若是只有一个定义在应用程序上下文它不须要.

subject-principal-regex应该包含一个组。例如默认表达式"CN=(.*?)," 与常见的名称字段。若是证书的主题名称是"CN=Jimi Hendrix, OU=…​",这将给一个用户名"Jimi Hendrix",不分大小写。因此"emailAddress=(.?),"匹配"EMAILADDRESS=jimi@hendrix.org,CN=…​"给一个用户名"jimi@hendrix.org",若是客户端提供一个证书,成功提取有效的用户名,而后应该有一个有效的安全上下文中的Authentication对象.若是没有找到证书,或没有相应的用户可能会发现而后安全上下文仍将是空的。这意味着您能够轻松地使用 X.509年与其余选项,如基于表单的登陆身份验证.

在Tomcat中设置SSL

有一些证书的samples/certificate的目录在春季安全项目.您能够使用这些启用SSL进行测试若是你不想生成本身的.文件的服务器.jks包含服务器证书、私钥和发行证书的证书颁发机构.也有一些客户端证书文件从示例应用程序用户.你能够在你的浏览器安装这些启用SSL客户机身份验证.

在SSL支持下tomcat运行,降低的server.jks文件到tomcat的配置的目录并添加如下链接器的`server.xml`l的文件

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true"
			clientAuth="true" sslProtocol="TLS"
			keystoreFile="${catalina.home}/conf/server.jks"
			keystoreType="JKS" keystorePass="password"
			truststoreFile="${catalina.home}/conf/server.jks"
			truststoreType="JKS" truststorePass="password"
/>

若是你仍然但愿SSL链接成功clientAuth也能够被设置为want,即便客户没有提供一个证书。客户不提供证书将没法得到的任何对象的访问Spring Security,除非你使用一个non-X.509认证机制,如表单身份验证.

run - as验证替换

概述

AbstractSecurityInterceptor 可以暂时取代Authentication对象在SecurityContextSecurityContextHolder安全对象回调阶段。这只发生若是最初的Authentication 对象是成功处理的AuthenticationManagerAccessDecisionManager.RunAsManager将指示更换Authentication对象,若是有的话,应该使用在SecurityInterceptorCallback.

Configuration

Spring Security提供RunAsManager 接口:

Authentication buildRunAs(Authentication authentication, Object object,
	List<ConfigAttribute> config);

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);

第一个方法返回Authentication对象应该取代现有的身份验证的对象方法调用的持续时间。若是方法返回null,它代表你没有更换。第二种方法是使用AbstractSecurityInterceptor 启动验证配置属性的一部分。 supports(Class)的方法被调用以确保安全拦截器将安全对象实现配置的`RunAsManager支持的类型安全拦截器.

一个具体实现RunAsManager提供Spring Security,若是 ConfigAttribute从 RUN_AS_开始,RunAsManagerImpl的类返回一个替代RunAsUserToken.若是找到任何此类ConfigAttribute,替换“RunAsUserToken”将包含相同的主要,凭证,当局为最初的Authentication对象.伴随着一个新的GrantedAuthorityImpl 为每一个RUN_AS_ ConfigAttribute.每个新的GrantedAuthorityImpl将前缀 ROLE_,其次是RUN_AS ConfigAttribute.例如, RUN_AS_SERVER将致使更换RunAsUserToken包含ROLE_RUN_AS_SERVER授予权力.

替代RunAsUserToken就像任何其余身份验证的对象。须要验证的 Authentication ,可能经过一个合适的AuthenticationManager表明团。RunAsImplAuthenticationProvider 执行身份验证。它只是接受任何有效的 RunAsUserToken .

为了确保恶意代码不建立一个RunAsUserToken和如今它保证接受‘RunAsImplAuthenticationProvider,散列键存储在全部生成的令牌. RunAsManagerImplRunAsImplAuthenticationProvider 中建立bean相同的:

<bean id="runAsManager"
	class="org.springframework.security.access.intercept.RunAsManagerImpl">
<property name="key" value="my_run_as_password"/>
</bean>

<bean id="runAsAuthenticationProvider"
	class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
<property name="key" value="my_run_as_password"/>
</bean>

经过使用相同的密钥,每一个RunAsUserToken能够验证它是由一个RunAsManagerImpl批准。出于安全缘由 RunAsManagerImpl创造后是不可变的

Spring Security Crypto模块

引言

Spring Security Crypto模块提供了对称加密,支持密钥的生成、编码和密码。该代码是分布式的核心模块的一部分 但没有任何其余Spring Security (或Spring) 代码的依赖关系。

加密器

加密类提供了构造对称加密工厂方法,使用这个类 您能够建立字节加密器加密数据在byte[]形式, 你也能够构建textencryptors加密文本字符串,且加密是线程安全的。

BytesKeyGenerator

使用encryptors.standard工厂方法构建 "standard" 字节加密机:

Encryptors.standard("password", "salt");

"standard" 采用的加密方法是:256-bit AES using PKCS #5’s PBKDF2 (Password-Based Key Derivation Function #2). 这种方法要求 Java 6. 该密码用于生成密钥应存放在安全的地方,不能共享。salt是用来防止在事件中的密钥对密钥的字典攻击,你的加密的数据被泄露 一个16字节的随机初始化向量也适用,因此每一个加密的消息是惟一的。

所提供的salt应在十六进制编码的字符串形式,是随机的,并至少有8个字节的长度。这种salt能够用keygenerator生成。

String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded

TextEncryptor

使用encryptors.text工厂方法构建一个标准textencryptor:

Encryptors.text("password", "salt");
TextEncryptor使用一个标准的bytesencryptor加密文本数据。加密结果返回为十六进制编码的字符串,便于存储在文件系统或数据库中。

使用encryptors.queryabletext工厂方法构建一个“可查询”textencryptor:

Encryptors.queryableText("password", "salt");

一个可查询的textencryptor和标准textencryptor之间的差别作初始化向量 vector(iv) 处理.iv用于查询的textencryptor#加密操做是共享的,或不变的,而不是随机生成的。这意味着同一个文本加密的屡次将始终产生相同的加密结果。这是不太安全的,但须要对加密的数据,须要进行查询。可查询加密文本的一个例子是一个OAuth的apikey。

keygenerators

keygenerators类构造密钥生成器不一样类型提供了许多便利的工厂方法。 使用这个类,你能够建立一个byteskeygenerator生成byte[]秘钥。你也能够创建一个stringkeygenerator生成字符串键。keygenerators线程是安全的。

BytesKeyGenerator

使用keygenerators.securerandom工厂方法生成的实例byteskeygenerator提供支持:

KeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();

默认密钥长度为8字节.还有一个keygenerators.securerandom变异提供密钥长度控制:

KeyGenerators.secureRandom(16);

使用keygenerators.shared工厂方法来构建一个byteskeygenerator每次调用,老是返回相同的关键:

KeyGenerators.shared(16);

StringKeyGenerator

使用keygenerators.string工厂方法构建一个8字节,提供keygenerator进制编码,每一个键为字符串:

KeyGenerators.string();

passwordencoders

Spring Security Crypto模块的密码包提供了编码密码支持. PasswordEncoder 是中心的服务接口,并具备如下签名:

public interface PasswordEncoder {

String encode(String rawPassword);

boolean matches(String rawPassword, String encodedPassword);
}

若是rawpassword编码,等于encodedpassword,方法返回true,此方法的目的是支持基于密码的身份验证方案。

BCryptPasswordEncoder 实现使用普遍支持的“BCrypt”算法哈希密码。BCrypt的使用16字节的随机salt值是故意减慢的算法,以阻碍密码破解。它能够使用“强度”参数,从4到31的“强度”参数来调整它的数量。值越高,就必须作更多的工做来计算哈希值。默认值为10。您能够在部署的系统中更改此值,而不影响现有的密码,由于该值也存储在编码的散列中

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
`Pbkdf2PasswordEncoder`实现使用PBKDF2算法哈希密码。为了战胜密码破解PBKDF2是故意慢的算法,调整须要。用5秒来验证你的系统上的密码。
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

并发支持

在大多数环境中,安全存储在每个 Thread 基础. 这意味着当工做是在一个新的 Thread,SecurityContext 失去了 Spring Security provides提供了一些基础设施,以帮助使这更容 易为用户,Spring Security提供了低级别的抽象,用于在多线程环境中使用 Spring Security,事实上,这是Spring Security创建与整合 AsyncContext.start(Runnable) 和 Spring MVC 异步集成.

DelegatingSecurityContextRunnable

最基本的建筑块内Spring Security’s并发支持DelegatingSecurityContextRunnable. 不包委托Runnable为了初始化的SecurityContextHolder 用指定的SecurityContext为表明。而后调用委托运行保障明确SecurityContextHolder之后DelegatingSecurityContextRunnable 有些东西看起来就像这样:

public void run() {
try {
	SecurityContextHolder.setContext(securityContext);
	delegate.run();
} finally {
	SecurityContextHolder.clearContext();
}
}

虽然很简单,但这使得它无缝的securitycontext从一个线程转移到另外一个。这很重要,由于,在大多数状况下,每一个线程的基础上的securitycontextholder行为均可能使用了Spring Security的 <global-method-security> 来支持你的服务,你如今能够很容易地转移 SecurityContext 当前 Thread到 Thread 调用安全服务。下面是你如何作这件事的一个例子:

Runnable originalRunnable = new Runnable() {
public void run() {
	// invoke secured service
}
};

SecurityContext context = SecurityContextHolder.getContext();
DelegatingSecurityContextRunnable wrappedRunnable =
	new DelegatingSecurityContextRunnable(originalRunnable, context);

new Thread(wrappedRunnable).start();

上面的代码执行如下步骤:

  • 建立一个Runnable 这是咱们的invoking安全服务,但请注意这是不相关的Spring Security。

  • 得到SecurityContext咱们但愿从SecurityContextHolder中初始化DelegatingSecurityContextRunnable

  • 使用DelegatingSecurityContextRunnable建立一个线程。

  • 自从建立了DelegatingSecurityContextRunnableSecurityContextSecurityContextHolder这里有一个快捷方式的构造函数,下面的代码与前面的代码相同:

Runnable originalRunnable = new Runnable() {
public void run() {
	// invoke secured service
}
};

DelegatingSecurityContextRunnable wrappedRunnable =
	new DelegatingSecurityContextRunnable(originalRunnable);

new Thread(wrappedRunnable).start();

咱们有的代码是简单使用的,但它仍然须要使用咱们的 Spring Security知识。 在下一节中,咱们将看看咱们如何利用DelegatingSecurityContextExecutor隐藏的因素来使用Spring Security。

DelegatingSecurityContextExecutor

在前面的章节中,咱们发现,它是很容易使用的DelegatingSecurityContextRunnable,但它是不理想,不方便的,由于咱们必须意识到Spring Security 是为了使用它.让咱们看看DelegatingSecurityContextExecutor如何能屏蔽咱们的任何代码知识,若是咱们使用Spring Security.

设计DelegatingSecurityContextExecutor是很是类似于DelegatingSecurityContextRunnable除非它接受委托Executor而不是一个表明Runnable。你能够看到一个例子,它可能会被用在下面:

SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication =
	new UsernamePasswordAuthenticationToken("user","doesnotmatter", AuthorityUtils.createAuthorityList("ROLE_USER"));
context.setAuthentication(authentication);

SimpleAsyncTaskExecutor delegateExecutor =
	new SimpleAsyncTaskExecutor();
DelegatingSecurityContextExecutor executor =
	new DelegatingSecurityContextExecutor(delegateExecutor, context);

Runnable originalRunnable = new Runnable() {
public void run() {
	// invoke secured service
}
};

executor.execute(originalRunnable);

该代码执行如下步骤:

  • 建立SecurityContext用于咱们的DelegatingSecurityContextExecutor。请注意,在这个例子中,咱们简单地手工建立SecurityContext。然而在哪里或者怎么获得并不重要SecurityContext (i.e. 咱们能够从这里得到SecurityContextHolder 若是咱们想要)。

  • 建立一个delegateexecutor是在执行提交`Runnable``s

  • 最后咱们建立一个 DelegatingSecurityContextExecutor这是在包装任何运行,传递到执行的方法DelegatingSecurityContextRunnable. 在这个实例中,将包里的delegateexec运行, SecurityContext 将每个Runnable提交给咱们 DelegatingSecurityContextExecutor. 若是咱们运行后台任务,须要由一个具备提高权限的用户运行,这是很是好的,

  • 在这一点上,你可能会问本身 "我该如何保护我所学过的 Spring Security代码知识?"来代替建立SecurityContext`andthe`DelegatingSecurityContextExecutor 在咱们的代码中, 咱们能够注入一个已经初始化的实例DelegatingSecurityContextExecutor.

@Autowired
private Executor executor; // becomes an instance of our DelegatingSecurityContextExecutor

public void submitRunnable() {
Runnable originalRunnable = new Runnable() {
	public void run() {
	// invoke secured service
	}
};
executor.execute(originalRunnable);
}

如今咱们的代码是不可知的 SecurityContext 正在传播到Thread,而后originalRunnable 被执行,而后SecurityContextHolder 被清除。在这个示例中,同一个用户正在被用于执行每一个线程.若是咱们想使用户从 SecurityContextHolder at the time we invoked executor.execute(Runnable) (i.e. the currently logged in user) 处理 originalRunnable? 是能够作到的 removing the SecurityContext咱们的争论是 DelegatingSecurityContextExecutor构造函数,好比:

SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor();
DelegatingSecurityContextExecutor executor =
	new DelegatingSecurityContextExecutor(delegateExecutor);

如今任什么时候候 executor.execute(Runnable) 执行 SecurityContext 是首先得到的 SecurityContextHolder 而后 SecurityContext 是用来建立 DelegatingSecurityContextRunnable的. 这意味着咱们正在执行的 Runnable 使用相同的用户来调用 executor.execute(Runnable) 代码.

Spring Security Concurrency 并发类

指javadoc额外的集成与java并发API和Spring的抽象任务,一旦你理解了之前的代码你会发现,他们的解释是很单一的。

  • DelegatingSecurityContextCallable

  • DelegatingSecurityContextExecutor

  • DelegatingSecurityContextExecutorService

  • DelegatingSecurityContextRunnable

  • DelegatingSecurityContextScheduledExecutorService

  • DelegatingSecurityContextSchedulingTaskExecutor

  • DelegatingSecurityContextAsyncTaskExecutor

  • DelegatingSecurityContextTaskExecutor

Spring MVC 整合

Spring Security 本节涵盖了进一步的细节的集成, 提供了一些可选的集成与Spring MVC

@EnableWebMvcSecurity

Spring Security 4.0, @EnableWebMvcSecurity 是 很差的. 更换 @EnableWebSecurity w这决定将基于加入Spring MVC的特色。

使MVC和Spring Security更好的整合与集成@EnableWebSecurity 对你的配置的注释。

Spring Security 提供配置使用 Spring MVC’s WebMvcConfigurerAdapter. 这意味着,若是你使用的是更高级的选项,如 WebMvcConfigurationSupport ,那么你将须要手动提供 Spring Security 配置.

MvcRequestMatcher

Spring Security 提供如何深度整合Spring MVC 匹配的网址和 MvcRequestMatcher. 这是有帮助的,以确保您的Security规则匹配用于处理您的请求的逻辑.

它老是建议提供受权规则匹配的HttpServletRequest和方法的安全性.

经过匹配提供受权规则HttpServletRequest是很好的,由于它很早就发生在代码路径,https://en.wikipedia.org/wiki/Attack_surface[attack surface].方法安全性确保若是有人绕过了Web权限规则,您的应用程序仍然是安全的. 这是你该知道的 Defence in Depth

考虑一个控制器映射以下:

@RequestMapping("/admin")
public String admin() {

若是咱们想经过限制访问该控制器的方法来管理用户, 一个开发人员能够经过匹配的 HttpServletRequest 获得如下的:

protected configure(HttpSecurity http) throws Exception {
	http
		.authorizeRequests()
			.antMatchers("/admin").hasRole("ADMIN");
}

或者在xml中

<http>
	<intercept-url pattern="/admin" access="hasRole('ADMIN')"/>
</http>

任何配置URL /admin将通过身份验证的用户做为管理用户. 然而, 这取决于咱们 Spring MVC配置, URL /admin.html也会告诉咱们admin() 方法.

问题是,咱们的安全规则只是保护 /admin. 咱们能够为全部的排列添加额外的规则 Spring MVC,但这将是至关冗长而乏味的.

相反,咱们能够利用Spring Security’s MvcRequestMatcher. 下面的配置会保护,Spring MVC将匹配利用Spring MVC匹配URL的URL。

protected configure(HttpSecurity http) throws Exception {
	http
		.authorizeRequests()
			.mvcMatchers("/admin").hasRole("ADMIN");
}

在XML中:

<http request-matcher="mvc">
	<intercept-url pattern="/admin" access="hasRole('ADMIN')"/>
</http>

@AuthenticationPrincipal

Spring Security provides AuthenticationPrincipalArgumentResolver 能解决问题 Authentication.getPrincipal() 对于 Spring MVC 争论. 经过使用 @EnableWebSecurity 您将自动将此添加到您的 Spring MVC 配置. 若是你使用 XML 基于你的配置, 你必须本身添加这个。例如:

<mvc:annotation-driven>
		<mvc:argument-resolvers>
				<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
		</mvc:argument-resolvers>
</mvc:annotation-driven>

一旦 AuthenticationPrincipalArgumentResolver 是正确配置的,您能够彻底完成 Spring Security 在Spring MVC层。

考虑一个自定义的状况 UserDetailsService返回一个 Object 实现 UserDetails 你本身的 CustomUser Object. 和 CustomUser 当前已验证的用户能够使用如下代码访问:

@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser() {
	Authentication authentication =
	SecurityContextHolder.getContext().getAuthentication();
	CustomUser custom = (CustomUser) authentication == null ? null : authentication.getPrincipal();

	// .. find messags for this user and return them ...
}

至于 Spring Security 3.2 咱们能够更直接地经过添加注释来解决这个问题。例如:

import org.springframework.security.core.annotation.AuthenticationPrincipal;

// ...

@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {

	// .. find messags for this user and return them ...
}

有时,它多是必要的,以某种方式来改造. 好比, 若是 CustomUser 须要是最终它不能被扩展。 在这种状况下 UserDetailsService 可能会返回一个 Object 实现 UserDetails并提供了一个命名的方法 getCustomUser 访问 CustomUser. 好比,他看起来是这个样子的:

public class CustomUserUserDetails extends User {
		// ...
		public CustomUser getCustomUser() {
				return customUser;
		}
}

而后,咱们能够访问 CustomUser 使用 SpEL expression 使用 Authentication.getPrincipal() 做为根对象:

import org.springframework.security.core.annotation.AuthenticationPrincipal;

// ...

@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal(expression = "customUser") CustomUser customUser) {

	// .. find messags for this user and return them ...
}

咱们能够进一步消除咱们的依赖 Spring Security经过标记 @AuthenticationPrincipal 咱们有咱们本身的元注释注释. 下面,咱们展现了如何咱们能够这样作的注释命名 @CurrentUser.

NOTE:重要的是要认识到消除依赖 Spring Security,它是将建立的消耗应用程序 @CurrentUser. 这一步不是严格要求,但有助于隔离你的依赖 Spring Security 到一个更重要的位置.

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {}

如今@CurrentUser 已指定, 咱们能够用它来信号来解决咱们的 CustomUser当前已验证的用户孤立了咱们依赖 Spring Security 到一个单一的文件.

@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@CurrentUser CustomUser customUser) {

	// .. find messags for this user and return them ...
}

Spring MVC 异步集成

Spring Web MVC 3.2+ 有极好的支持 Asynchronous Request Processing. 没有额外的配置, Spring Security 将自动设置 SecurityContext 到 Thread执行 Callable 由你的控制器返回. 例如,下面的方法将自动有它的 Callable 执行的 SecurityContext 这是可用的,当 Callable 被建立:

@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

return new Callable<String>() {
	public Object call() throws Exception {
	// ...
	return "someView";
	}
};
}
Associating SecurityContext to Callable’s

从技术上讲, Spring Security 结合 WebAsyncManagerSecurityContext这是用来处理 Callable 是 SecurityContext 存在于 SecurityContextHolder 此时 startCallableProcessing 被调用.

没有一个自动集成与 DeferredResult由控制器返回. 这是由于 DeferredResult 是由用户处理的,所以没有自动整合的方式。 固然, 你依然能够用 Concurrency Support提供透明的集成与 Spring Security.

Spring MVC 和 CSRF 整合

自动令牌包

Spring Security 将自动 include the CSRF Token 使用形式为 Spring MVC form tag. 好比说, 下面的 JSP:

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
	xmlns:c="http://java.sun.com/jsp/jstl/core"
	xmlns:form="http://www.springframework.org/tags/form" version="2.0">
	<jsp:directive.page language="java" contentType="text/html" />
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
	<!-- ... -->

	<c:url var="logoutUrl" value="/logout"/>
	<form:form action="${logoutUrl}"
		method="post">
	<input type="submit"
		value="Log out" />
	<input type="hidden"
		name="${_csrf.parameterName}"
		value="${_csrf.token}"/>
	</form:form>

	<!-- ... -->
</html>
</jsp:root>

将输出HTML,相似于下面的代码:

<!-- ... -->

<form action="/context/logout" method="post">
<input type="submit" value="Log out"/>
<input type="hidden" name="_csrf" value="f81d4fae-7dec-11d0-a765-00a0c91e6bf6"/>
</form>

<!-- ... -->

解决 CsrfToken

Spring Security 提供 CsrfTokenArgumentResolver 就能自动解决 CsrfToken Spring MVC 争论. 经过使用 @EnableWebSecurity 您将自动将此添加到您的 Spring MVC 配置. 若是你使用基于XML的配置,您必须本身手动添加.

一旦 CsrfTokenArgumentResolver 是正确配置的,你能够暴露 CsrfToken 你的静态HTML为基础的应用.

@RestController
public class CsrfController {

	@RequestMapping("/csrf")
	public CsrfToken csrf(CsrfToken token) {
		return token;
	}
}

重要的是要保持 CsrfToken 从其余域的一个秘密. 这意味着若是你正在使https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[Cross Origin Sharing (CORS)], 你应该 NOT 暴露 CsrfToken 到任何外部域.

Spring Data 整合

Spring Security 提供 Spring Data整合容许在您的查询中引用当前的用户. 它颇有用,但要包括在查询用户支持分页结果因为过滤后,结果规模不会减小。

Spring 数据 & Spring 安全配置

要使用这种支持,提供一个类型的 SecurityEvaluationContextExtension. 在Java配置中, 他看起来会是这个样子:

@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
	return new SecurityEvaluationContextExtension();
}

在XMl配置中, 他看起来会是这个样子:

<bean class="org.springframework.security.data.repository.query.SecurityEvaluationContextExtension"/>

安全的表达 @Query

现在 Spring Security 能够在您的查询中使用,例如:

@Repository
public interface MessageRepository extends PagingAndSortingRepository<Message,Long> {
	@Query("select m from Message m where m.to.id = ?#{ principal?.id }")
	Page<Message> findInbox(Pageable pageable);
}

检查 Authentication.getPrincipal().getId()看看是否 平等于容器 Message. 请注意,这个示例假定您已定制了一个对象的,该对象是具备一个身份属性. 经过暴露 SecurityEvaluationContextExtension bean, 全部的Common Security Expressions 可用在 Query.

Appendix

安全数据库模式

有使用的框架和本附录提供了一个单一的参考点和给 他们全部的不一样的数据库模式. 你只须要为你须要的部分提供functonality表.

DDL声明给出了 HSQLDB 数据库.您能够使用这些做为定义您正在使用的数据库的架构的指导方针.

用户模式

JDBC 的标准实现了UserDetailsService (JdbcDaoImpl) 须要表加载密码, 账户状态(可用或者不可用)和权力名单 (角色) 给用户. 您将须要调整此架构以与您正在使用的数据库语言相匹配.

create table users(
	username varchar_ignorecase(50) not null primary key,
	password varchar_ignorecase(50) not null,
	enabled boolean not null
);

create table authorities (
	username varchar_ignorecase(50) not null,
	authority varchar_ignorecase(50) not null,
	constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);

集团机关

Spring Security 2.0 介绍了当前组支持 JdbcDaoImpl.若是组启用表,结构以下. 您将须要调整此架构以与您正在使用的数据库语言相匹配.

create table groups (
	id bigint generated by default as identity(start with 0) primary key,
	group_name varchar_ignorecase(50) not null
);

create table group_authorities (
	group_id bigint not null,
	authority varchar(50) not null,
	constraint fk_group_authorities_group foreign key(group_id) references groups(id)
);

create table group_members (
	id bigint generated by default as identity(start with 0) primary key,
	username varchar(50) not null,
	group_id bigint not null,
	constraint fk_group_members_group foreign key(group_id) references groups(id)
);

请记住,这些表只须要由您使用所提供的JDBC UserDetailsService 实施. 若是你本身写或选择实施 AuthenticationProvider 没有 UserDetailsService,而后只要接口的合同是满意的,你有完整的自由来存储的数据。

持续登陆 (记住我) Schema

此表用于存储更安全的使用的数据 persistent token remember-me 实施. 若是你正在使用 JdbcTokenRepositoryImpl 不管是直接或经过命名空间,您都将须要此表. 请记住调整此架构以与您正在使用的数据库语言相匹配.

create table persistent_logins (
	username varchar(64) not null,
	series varchar(64) primary key,
	token varchar(64) not null,
	last_used timestamp not null
);

ACL Schema

有四个表所使用 Spring Security ACL 实施.

  1. acl_sid Store身份确认和安全经过ALC系统来保障, 这些能够适用于惟一的或者多个负责人。

  2. acl_class定义域的对象类型的ACL应用。 class列储存java类对象名称。

  3. acl_object_identity 储存的具体领域对象的标识的定义.

  4. acl_entry 储存的ACL权限适用于一个特定的对象标识和安全标识。

它假定数据库将自动生成每一个身份的主键。 JdbcMutableAclService 必须可以检索这些时,它已建立了一个新的行 acl_sid或者 acl_class表。它有两个属性定义须要检索这些值的SQL classIdentityQuery 和 sidIdentityQuery. 这两个默认 call identity()

ACL加工建立JRC包含在hypersql建立ACL模式的文件 (HSQLDB), PostgreSQL, MySQL/MariaDB, Microsoft SQL Server, and Oracle 数据库。 这些架构也被证实在如下几个部分.

HyperSQL

默认架构的工做,采用的是单元测试的框架内嵌入的HSQLDB数据库.

create table acl_sid(
	id bigint generated by default as identity(start with 100) not null primary key,
	principal boolean not null,
	sid varchar_ignorecase(100) not null,
	constraint unique_uk_1 unique(sid,principal)
);

create table acl_class(
	id bigint generated by default as identity(start with 100) not null primary key,
	class varchar_ignorecase(100) not null,
	constraint unique_uk_2 unique(class)
);

create table acl_object_identity(
	id bigint generated by default as identity(start with 100) not null primary key,
	object_id_class bigint not null,
	object_id_identity bigint not null,
	parent_object bigint,
	owner_sid bigint,
	entries_inheriting boolean not null,
	constraint unique_uk_3 unique(object_id_class,object_id_identity),
	constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
	constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
	constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
);

create table acl_entry(
	id bigint generated by default as identity(start with 100) not null primary key,
	acl_object_identity bigint not null,
	ace_order int not null,
	sid bigint not null,
	mask integer not null,
	granting boolean not null,
	audit_success boolean not null,
	audit_failure boolean not null,
	constraint unique_uk_4 unique(acl_object_identity,ace_order),
	constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
	constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
);

PostgreSQL

create table acl_sid(
	id bigserial not null primary key,
	principal boolean not null,
	sid varchar(100) not null,
	constraint unique_uk_1 unique(sid,principal)
);

create table acl_class(
	id bigserial not null primary key,
	class varchar(100) not null,
	constraint unique_uk_2 unique(class)
);

create table acl_object_identity(
	id bigserial primary key,
	object_id_class bigint not null,
	object_id_identity bigint not null,
	parent_object bigint,
	owner_sid bigint,
	entries_inheriting boolean not null,
	constraint unique_uk_3 unique(object_id_class,object_id_identity),
	constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
	constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
	constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
);

create table acl_entry(
	id bigserial primary key,
	acl_object_identity bigint not null,
	ace_order int not null,
	sid bigint not null,
	mask integer not null,
	granting boolean not null,
	audit_success boolean not null,
	audit_failure boolean not null,
	constraint unique_uk_4 unique(acl_object_identity,ace_order),
	constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
	constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
);

你将不得不分别地设置 classIdentityQuery和 sidIdentityQuery 性能 JdbcMutableAclService 如下的值, :

  • select currval(pg_get_serial_sequence('acl_class', 'id'))

  • select currval(pg_get_serial_sequence('acl_sid', 'id'))

MySQL and MariaDB

CREATE TABLE acl_sid (
	id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	principal BOOLEAN NOT NULL,
	sid VARCHAR(100) NOT NULL,
	UNIQUE KEY unique_acl_sid (sid, principal)
) ENGINE=InnoDB;

CREATE TABLE acl_class (
	id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	class VARCHAR(100) NOT NULL,
	UNIQUE KEY uk_acl_class (class)
) ENGINE=InnoDB;

CREATE TABLE acl_object_identity (
	id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	object_id_class BIGINT UNSIGNED NOT NULL,
	object_id_identity BIGINT NOT NULL,
	parent_object BIGINT UNSIGNED,
	owner_sid BIGINT UNSIGNED,
	entries_inheriting BOOLEAN NOT NULL,
	UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity),
	CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
	CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
	CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
) ENGINE=InnoDB;

CREATE TABLE acl_entry (
	id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	acl_object_identity BIGINT UNSIGNED NOT NULL,
	ace_order INTEGER NOT NULL,
	sid BIGINT UNSIGNED NOT NULL,
	mask INTEGER UNSIGNED NOT NULL,
	granting BOOLEAN NOT NULL,
	audit_success BOOLEAN NOT NULL,
	audit_failure BOOLEAN NOT NULL,
	UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order),
	CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
	CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
) ENGINE=InnoDB;

Microsoft SQL Server

CREATE TABLE acl_sid (
	id BIGINT NOT NULL IDENTITY PRIMARY KEY,
	principal BIT NOT NULL,
	sid VARCHAR(100) NOT NULL,
	CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
);

CREATE TABLE acl_class (
	id BIGINT NOT NULL IDENTITY PRIMARY KEY,
	class VARCHAR(100) NOT NULL,
	CONSTRAINT uk_acl_class UNIQUE (class)
);

CREATE TABLE acl_object_identity (
	id BIGINT NOT NULL IDENTITY PRIMARY KEY,
	object_id_class BIGINT NOT NULL,
	object_id_identity BIGINT NOT NULL,
	parent_object BIGINT,
	owner_sid BIGINT,
	entries_inheriting BIT NOT NULL,
	CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
	CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
	CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
	CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
);

CREATE TABLE acl_entry (
	id BIGINT NOT NULL IDENTITY PRIMARY KEY,
	acl_object_identity BIGINT NOT NULL,
	ace_order INTEGER NOT NULL,
	sid BIGINT NOT NULL,
	mask INTEGER NOT NULL,
	granting BIT NOT NULL,
	audit_success BIT NOT NULL,
	audit_failure BIT NOT NULL,
	CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
	CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
	CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
);

Oracle Database

CREATE TABLE acl_sid (
	id NUMBER(38) NOT NULL PRIMARY KEY,
	principal NUMBER(1) NOT NULL CHECK (principal in (0, 1)),
	sid NVARCHAR2(100) NOT NULL,
	CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
);
CREATE SEQUENCE acl_sid_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_sid_id_trigger
	BEFORE INSERT ON acl_sid
	FOR EACH ROW
BEGIN
	SELECT acl_sid_sequence.nextval INTO :new.id FROM dual;
END;

CREATE TABLE acl_class (
	id NUMBER(38) NOT NULL PRIMARY KEY,
	class NVARCHAR2(100) NOT NULL,
	CONSTRAINT uk_acl_class UNIQUE (class)
);
CREATE SEQUENCE acl_class_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_class_id_trigger
	BEFORE INSERT ON acl_class
	FOR EACH ROW
BEGIN
	SELECT acl_class_sequence.nextval INTO :new.id FROM dual;
END;

CREATE TABLE acl_object_identity (
	id NUMBER(38) NOT NULL PRIMARY KEY,
	object_id_class NUMBER(38) NOT NULL,
	object_id_identity NUMBER(38) NOT NULL,
	parent_object NUMBER(38),
	owner_sid NUMBER(38),
	entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
	CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
	CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
	CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
	CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
);
CREATE SEQUENCE acl_object_identity_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_object_identity_id_trigger
	BEFORE INSERT ON acl_object_identity
	FOR EACH ROW
BEGIN
	SELECT acl_object_identity_sequence.nextval INTO :new.id FROM dual;
END;

CREATE TABLE acl_entry (
	id NUMBER(38) NOT NULL PRIMARY KEY,
	acl_object_identity NUMBER(38) NOT NULL,
	ace_order INTEGER NOT NULL,
	sid NUMBER(38) NOT NULL,
	mask INTEGER NOT NULL,
	granting NUMBER(1) NOT NULL CHECK (granting in (0, 1)),
	audit_success NUMBER(1) NOT NULL CHECK (audit_success in (0, 1)),
	audit_failure NUMBER(1) NOT NULL CHECK (audit_failure in (0, 1)),
	CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
	CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
	CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
);
CREATE SEQUENCE acl_entry_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_entry_id_trigger
	BEFORE INSERT ON acl_entry
	FOR EACH ROW
BEGIN
	SELECT acl_entry_sequence.nextval INTO :new.id FROM dual;
END;

安全空间

本附录提供了在安全命名空间中可用的元素以及它们建立的基础上的信息的元素的引用 (个别类的知识,和他们是如何一块儿工做的,假设你能够找到项目中的javadoc更多信息和本文档中的其余部分)。 若是您之前没有使用过命名空间,请阅读这部分。 introductory chapter 对命名空间的配置, 这是做为一个补充的信息。 使用一个很好的质量的XML编辑器,同时编辑一个基于架构的配置建议,这将提供有关的元素和属性的上下文信息,以及解释他们的目的。 命名空间是写在 RELAX NG 的紧凑的格式,后来转为XSD架构. 若是您对这种格式很熟悉,您可能但愿检查它。 schema file 直接。

Web应用安全

<debug>

启用Spring Security调试基础设施。这将给人类提供可读的 (多线) 调试信息以监视安全筛选器的请求. 这可能包括敏感信息,如请求参数或头文件,而且只在开发环境中使用。

<http>

若是你能使用 <http> 在您的应用程序中的元素 FilterChainProxy bean 叫作 "springSecurityFilterChain"建立和元素内的配置是用来在内部创建一个过滤器链 FilterChainProxy. 做为Spring Security 3.1, 额外的 http 元素能够用来添加额外的过滤链脚注:[ See the introductory chapter 为你创建映射 web.xml ]. 一些核心过滤器老是在一个过滤器链中建立,其余一些核心过滤器将被添加到堆栈中,这取决于当前的属性和子元素. 标准过滤器的位置是固定的 (看 the filter order table 在命名空间介绍中,删除一个与之前版本的框架的常见错误源,当用户在该框架中明确地配置了过滤器链时 FilterChainProxybean.若是你须要彻底控制配置的话,你仍然能够这样作。

所须要参考全部过滤器 AuthenticationManager将自动注入由命名空间配置建立的内部实例(看到introductory chapter 为更多的 AuthenticationManager).每一个<http>命名空间块老是建立一个SecurityContextPersistenceFilter,一个 ExceptionTranslationFilter和一个FilterSecurityInterceptor. 这些都是固定的,不能被替代品替代

<http> 属性

<http>的属性元素控制核心过滤器上的一些属性。

  • access-decision-manager-ref 可选属性指定的标识 AccessDecisionManager 实现应该用于受权的HTTP请求. 经过一个默认的 AffirmativeBased 实现用于与一个 RoleVoter和 AuthenticatedVoter.

  • authentication-manager-ref 参考的 AuthenticationManager 用来 FilterChain 经过这个HTTP元素建立。

  • auto-config 自动注册登陆表单,基本认证,注销服务。若是设置为“真”,全部这些功能都被添加 (虽然您仍然能够经过提供相应的元素来自定义每一个元素的配置)。若是未指定,默认为“假”。不建议使用此属性。使用明确的配置元素,而不是避免混乱。

  • create-session 控制一个Spring Security类的建立,包括如下:

    • always - Spring Security 若是不存在,将主动建立一个会话。

    • ifRequired -Spring Security只会建立一个会话,若是是必需的 (默认值)。

    • never - Spring Security 永远不会建立一个会话, 若是是应用程序它将会使用一个会话。

    • stateless - Spring Security 不会建立一个会话,忽略得到一个会话的会话Spring。 Authentication.

  • disable-url-rewriting 防止会话标识被添加到应用程序中的网址。 客户端必须使用该属性设置为 true. 默认值是 true.

  • entry-point-ref 一般状况下 AuthenticationEntryPoint 使用的将取决于已配置的身份验证机制。 此属性容许这种行为是经过定义一个定制的重写 AuthenticationEntryPoint bean 这将启动认证过程。

  • jaas-api-provision 若是可用,运行请求做为 Subject 得到的 JaasAuthenticationToken这是经过添加一个 JaasApiIntegrationFilter bean 到堆栈。默认值为 false.

  • name 一个bean标识符,用于指在上下文中的其余地方的bean.

  • once-per-request 对应于 observeOncePerRequest 财产 FilterSecurityInterceptor. 默认值为 true.

  • pattern 定义一个模式 http 元素控制将被过滤的请求经过它定义的过滤器列表。解释是依赖于配置的 request-matcher. 若是没有定义模式,全部的请求都将被匹配,因此最具体的模式应该首先声明。

  • realm 设置用于基自己份验证的域名称 (若是启用). 对应于 realmName 财产 BasicAuthenticationEntryPoint.

  • request-matcher 定义 RequestMatcher 战略中使用的 FilterChainProxy 由 intercept-url建立的bean匹配传入的请求。 选择目前 mvcantregex 和 ciRegex, Spring MVC, ant, 正则表达式和不区分大小写的正则表达式。为每一个建立一个单独的实例intercept-url 元素的使用 pattern 和 method 属性,Ant路径匹配使用 AntPathRequestMatcher 和正则表达式匹配使用 RegexRequestMatcher. 看到这些类Javadoc详情究竟如何进行匹配。Ant路径是默认策略。

  • request-matcher-ref 一个参考到bean的实现 RequestMatcher 这将决定是否 FilterChain应使用, 这是一个更强大的替代。 pattern.

  • security 一个请求模式能够被映射到一个空的过滤链,经过设置这个属性 none. 没有安全将被应用,没有Spring Security的功能将是可用的。

  • security-context-repository-ref 容许注入一个自定义 SecurityContextRepository 进入 SecurityContextPersistenceFilter.

  • servlet-api-provision 提供的版本 HttpServletRequest 安全方法,如 isUserInRole()和 getPrincipal()这是经过添加一个 SecurityContextHolderAwareRequestFilter bean 到堆栈。默认值为 true.

<access-denied-handler>

此元素容许您设置 errorPage 默认属性 AccessDeniedHandler 经过使用 ExceptionTranslationFilter,使用 error-page 属性,或使用该属性提供您本身的实现。ref属性。这会在更详细的章节中讨论。 ExceptionTranslationFilter.

父元素 <access-denied-handler>
<access-denied-handler> Attributes
  • error-page 访问被拒绝页,一个通过验证的用户将被重定向到他们请求的一个没有权限访问的页面。

  • ref 定义一个引用 Spring bean 类型 AccessDeniedHandler.

<cors>

此元素容许配置 CorsFilter. 若是不 CorsFilter或者 CorsConfigurationSource 是指定在Spring MVC类路径中, a HandlerMappingIntrospector 被用做 CorsConfigurationSource.

<cors> 属性

<cors>的属性元素控制头元素。

  • ref 指定一个指定的名称的属性的可选属性 CorsFilter.

  • ref 指定一个指定的名称的属性的可选属性 CorsConfigurationSource 被注入到一个 CorsFilter 由XML命名空间建立。

父元素 <cors>

<headers>

此元素容许配置额外的 (security) 将发送的标题与响应。 它能够方便地配置几个头文件,也容许经过设置自定义头 header,能够发如今 Security Headers 参考截面。

  • Cache-ControlPragma,和 Expires - 能够设置使用 cache-control元。这将确保浏览器不缓存您的安全页。

  • Strict-Transport-Security - 能够设置使用 hsts元。这保证了浏览器自动请求将来要求HTTPS。

  • X-Frame-Options - 能够设置使用 frame-options 元 X-Frame-Options 能够用来阻止clickjacking攻击。

  • X-XSS-Protection -能够用来设置 xss-protection元 X-XSS-Protection 能够经过浏览器来作基本的控制。

  • X-Content-Type-Options -能够用来设置 content-type-options元。 X-Content-Type-Options 标头防止Internet Explorer MIME嗅探响应从宣布的内容类型。当下载扩展时这也适用于谷歌浏览器。

  • Public-Key-Pinning or Public-Key-Pinning-Report-Only -能够用来设置 hpkp 元。 这容许攻击者使用HTTPS的网站经过发布虚假证书的MIS或抵抗冒充。

  • Content-Security-Policy或 Content-Security-Policy-Report-Only -能够用来设置 content-security-policy element. Content Security Policy (CSP) 是一种机制,Web应用程序能够利用减轻内容注入漏洞,如跨站脚本(XSS)。

<headers> 属性

<headers>的属性元控制头元素。

  • defaults-disabled 可选属性,指定要禁用默认的Spring Security的HTTP响应头。默认是错误的 (包含默认标题)。

  • disabled 可选属性,指定要禁用Spring Security的HTTP响应头。默认是错误的(标题是启用的)。

父元素 <headers>

<cache-control>

添加 Cache-ControlPragma, 和 Expires 标头,以确保浏览器不缓存您的安全页。

<cache-control> 属性
  • disabled 指定是否禁用缓存控件。默认的错误。

父元素 <cache-control>

<hsts>

当能够添加时 Strict-Transport-Security 对任何安全请求的响应的标头。这容许服务器指示浏览器自动使用HTTPS为将来的要求。

<hsts> 属性
  • disabled 指定是否禁用严格的传输安全性。默认的错误。

  • include-sub-domains 指定区域应包括。默认为true。

  • max-age-seconds 指定时间的主人应该是已知的最大量HSTS主机。默认一年。

  • request-matcher-ref requestmatcher实例若是被用来肯定标题应设置,HttpServletRequest.isSecure()的默认值为真。

父元素 <hsts>

<hpkp>

当可以添加 Public Key Pinning Extension for HTTP 对任何安全请求的响应的标头。这容许攻击者使用HTTPS的网站经过发布虚假证书的MIS或抵抗冒充。

<hpkp> 属性
  • disabled 指定HTTP(HPKP)公有键应禁用。默认为true。

  • include-sub-domains 指定区域应包括。默认的错误。

  • max-age-seconds 设置公有键引脚头的最大年龄指令的值。默认60天。

  • report-only 指定若是浏览器只应报告引脚验证失败。默认为true。

  • report-uri 指定的URI,浏览器应该报告PIN验证失败。

父元素 <hpkp>

<pins>

引脚列表。

子元素 <pins>

<pin>

指定使用base64编码SPKI指纹值和加密哈希算法的属性。

<pin> 属性
  • algorithm 密码散列算法。默认是SHA256。

父元素 <pin>

<content-security-policy>

当能够添加 Content Security Policy (CSP) 响应标头 CSP 是一种机制,Web应用程序能够利用减轻内容注入漏洞,如跨站脚本(XSS)。

<content-security-policy> 属性
  • policy-directives 对于内容安全策略头文件的安全策略指令(S)或若是报表只设置为真,则只使用头文件的内容安全策略报告。

  • report-only 设置为真,使内容安全策略报告只报告策略违规行为的标题。默认为假。

父元素 <content-security-policy>

<frame-options>

当能够添加 X-Frame-Options header的响应,这会使得浏览器作一些安全检查和预防 clickjacking 攻击。

<frame-options> 属性
  • disabled 若是禁用, 且不包括X帧选项报头,将默认为错误。

  • policy

    • DENY 页面不能被显示在一个框架中,不管该网站试图怎样作。当指定了帧选项策略时,这仍是默认值。

    • SAMEORIGIN 该页面只能在同一个页面上的同一个页面的框架中显示。

    • ALLOW-FROM origin 该页只能显示在指定的原点的框中。

    换言之,若是你指定了拒绝,不只将试图加载在一个框架中的页面失败时从其余网站加载,试图这样作会失败,从同一个网站加载。另外一方面,若是你指定的sameorigin,你仍然能够使用在一个框架网页只要站点包括在一个框架是做为一个相同的服务页面。

  • strategy 选择 AllowFromStrategy 来使用,当使用allow-from策略时。

    • static 使用一个单一的静态allow-from价值。该值能够经过 value属性.

    • regexp 若是他们被容许使用regelur表达验证传入的请求和。正则表达式能够经过 value 属性。 用于检索用于验证的值的请求参数能够被使用。 from-parameter.

    • whitelist一个逗号分离含有容许域列表。逗号分隔的能够经过设置 value属性。 请求参数用于检索的值来验证能够指定使用的 from-parameter.

  • ref 不是使用一个预约义的策略也能够使用一个自定义的` allowfromstrategy `。这个bean的引用能够经过ref属性指定。

  • value 要使用的值是用allow-from的。 strategy.

  • from-parameter 指定的请求参数的名称使用时,使用正则表达式或白名单的allow-from策略。

父元素 <frame-options>

<xss-protection>

添加 X-XSS-Protection header 协助防止响应 reflected / Type-1 Cross-Site Scripting (XSS) 攻击。 这不是一个对XSS攻击的充分保护!

<xss-protection> 属性
  • xss-protection-block 当true和XSS启用保护是真的,增长了mode=block的标头。这代表该页面不该该被加载的浏览器。当false和XSS启用保护是真的,页面仍然会呈现一个反映时检测到攻击但反应将被修改以防止攻击。请注意,有时有办法绕过这种模式,它能够常常次使阻塞页面更可取。

父元素 <xss-protection>

<content-type-options>

添加 X-Content-Type-Options 标头随着NOSNIFF值响应。 disables MIME-sniffing对 IE8+谷歌浏览器扩展。

<content-type-options> 属性
  • disabled 若是选择的指定类型没法使用,默认FALSE。

父元素 <content-type-options>

<header>

向响应中添加额外的头文件,须要指定名称和值。

<header-attributes> 属性
  • header-name 标头name 的名字。

  • value value 添加的标头。

  • ref 引用自定义实现的 HeaderWriter 接口。

父元素 <header>

<anonymous>

添加一个 AnonymousAuthenticationFilter to the stack and an AnonymousAuthenticationProvider. 须要的若是你正在使用 IS_AUTHENTICATED_ANONYMOUSLY 属性.

父元素 <anonymous>
<anonymous> 属性
  • enabled 使用默认的命名空间设置,匿名“身份验证”设施将自动启用。您能够使用此属性禁用它。

  • granted-authority 应分配给匿名请求的授予权限。一般,这是用来分配匿名请求特定的角色,它能够随后被用于受权决策。若是未设置,默认为 ROLE_ANONYMOUS.

  • key 提供者和过滤器之间的密钥共享。这通常不须要设置。若是未设置,则默认为一个安全的随机生成的值。这意味着设置这个值能够提升启动时间,当使用匿名功能,由于安全的随机值能够须要一段时间才能产生。

  • username 应分配给匿名请求的用户名。这容许被肯定的主要,这多是重要的日志记录和审计。若是未设置,默认为anonymousUser.

<csrf>将添加元素

http://en.wikipedia.org/wiki/Cross-site_request_forgery[Cross Site Request Forger (CSRF)] protection to the application. It also updates the default RequestCache to only replay "GET" requests upon successful authentication. Additional information can be found in the <<csrf,Cross Site Request Forgery (CSRF)>> section of the reference.
父元素 <csrf>
<csrf>属性
  • disabled 可选属性,指定要禁用的Spring Security的CSRF保护。默认值为假(CSRF保护功能)。这是强烈建议关闭CSRF保护功能。

  • token-repository-ref 使用的csrftokenrepository。默认值是 HttpSessionCsrfTokenRepository.

  • request-matcher-ref requestmatcher实例被用来肯定是否应使用CSRF。除了默认的是“GET”任何HTTP方法,“Trace”、“Head”、“Opitions”。

<custom-filter>

此元素用于将一个过滤器添加到筛选器链中。它不会建立任何额外的bean类,但被用来选择一个类型的bean javax.servlet.Filter已在应用程序上下文中定义,完整的细节能够在Spring Security维护的筛选器链中的特定位置处添加。 namespace chapter.

父元素 <custom-filter>
<custom-filter>属性
  • after 过滤器自定义过滤后,应放置在链中。此功能只须要高级用户,但愿混合本身的过滤器到安全过滤器链,并有一些知识的标准Spring Security过滤器。将筛选器名称映射到特定的Spring Security实现筛选器。

  • before 过滤器应当即在此以前,将自定义筛选器放置在链中。

  • position 若是你正在更换一个标准的过滤器。自定义筛选器应放置在链中的显式位置。

  • ref 定义了一个实现的Spring bean的参考 Filter.

<expression-handler>

定义 SecurityExpressionHandler若是启用基于表达式的访问控制,则将使用实例,若是默认实现(没有ACL支持)将用于不提供。

父元素 <expression-handler>
<expression-handler> 属性
  • ref 定义了一个实现的Spring Security的参考 SecurityExpressionHandler.

<form-login>

用来添加一个UsernamePasswordAuthenticationFilter 到过滤器堆栈和一个 LoginUrlAuthenticationEntryPoint 到应用程序的环境, If no attributes are supplied, a login page will be generated automatically at the URL若是没有提供属性,将在网址中自动生成登陆页 "/login" 脚注:[ 此功能是真的只是提供了方便,并不仅是用于生产 (在那里,一个视图技术将被选择,并能够用来提供一个自定义的登陆页面,这个类 DefaultLoginPageGeneratingFilter 是 负责显示登陆页面,将正常形式的登陆和/或OpenID若是须要提供登陆形式。 ] 该行为能够使用自定义 <form-login> Attributes.

父元素 <form-login>
<form-login> 属性
  • always-use-default-target 若是设置 true, t用户将始终从给定的值开始 default-target-url, 何到达登陆页面。映射到 alwaysUseDefaultTargetUrl 财产 UsernamePasswordAuthenticationFilter. 默认值是 false.

  • authentication-details-source-ref 参考一 AuthenticationDetailsSource将被认证过滤器使用。

  • authentication-failure-handler-ref 能够做为一种替代 authentication-failure-url, 给您一个身份验证失败后的导航流的彻底控制权。该值应该是一个 AuthenticationFailureHandler bean在应用程序上下文中。

  • authentication-failure-url 映射到 authenticationFailureUrl属性 UsernamePasswordAuthenticationFilter. 定义浏览器将被重定向到登陆失败的网址。默认值为 /login?error,自动登陆页面生成器自动处理,用一个错误信息从新绘制登陆页面。

  • authentication-success-handler-ref 这能够做为一种替代default-target-url 和 always-use-default-target, 给您一个成功的认证后的导航流的彻底控制。该值应该是一个 AuthenticationSuccessHandler bean在应用程序上下文中。默认状况下,实现 SavedRequestAwareAuthenticationSuccessHandler使用和注入 default-target-url.

  • default-target-url 映射到 defaultTargetUrl 特性 UsernamePasswordAuthenticationFilter. 若是没有设置,默认值是“/”(应用程序的根)。登陆后,用户将被带到这个网址,只要他们没有被要求登陆,且他们试图访问一个有抵押的资源,他们将被带到最初的请求的网址。

  • login-page 应该用来显示登陆页面的网址。映射到` loginformurl 特性 `LoginUrlAuthenticationEntryPoint. 默认值为 "/login".

  • login-processing-url 映射到 filterProcessesUrl 特性 UsernamePasswordAuthenticationFilter。默认值为 "/login"。

  • password-parameter 包含密码的请求参数的名称。默认为“password”。

  • username-parameter 包含用户名的请求参数的名称。默认为“username”。

  • authentication-success-forward-url 映射到 ForwardAuthenticationSuccessHandlerauthenticationSuccessHandler特性 UsernamePasswordAuthenticationFilter

  • authentication-failure-forward-url 映射到 ForwardAuthenticationFailureHandlerauthenticationFailureHandler 特性 UsernamePasswordAuthenticationFilter.

<http-basic>

添加一个 BasicAuthenticationFilter 和 BasicAuthenticationEntryPoint 对配置。后者将只用于做为配置入口点,若是未启用基于窗体的登陆。

父元素 <http-basic>
<http-basic> 属性
  • authentication-details-source-ref 参考 AuthenticationDetailsSource将使用认证过滤器。

  • entry-point-ref 设置 AuthenticationEntryPoint 用来 BasicAuthenticationFilter.

<http-firewall> 元

实现的顶层元素 HttpFirewall 进入 FilterChainProxy 由命名空间建立,默认实现应该适用于大多数应用程序。

<http-firewall> 属性
  • ref 定义了一个实现的Spring Bean的参考 HttpFirewall.

<intercept-url>

此元素用于定义应用程序和配置如何处理它们的“网址”模式的集合 ,它被用来构建 FilterInvocationSecurityMetadataSource 经过使用 FilterSecurityInterceptor. 它还负责配置 ChannelProcessingFilter 若是特定的URL须要经过HTTPS访问,例如。 当匹配指定的模式对传入的请求时,匹配是在声明的元素的顺序中完成的。因此最具体的匹配模式应该是第一个,最广泛的应该是最后一个。

父元素 <intercept-url>
<intercept-url> 属性
  • access 列出将要存储在该目录中的访问属性 FilterInvocationSecurityMetadataSource 用于定义的网址模式/方法组合。这应该是一个逗号分隔的安全配置属性(如角色名称)的列表。

  • filters 只能采起“none”的值,这将致使任何匹配的请求,彻底绕过Spring Security过滤器链。没有其余的` <HTTP> ` 配置将有影响的请求,将没有安全上下文可供其持续时间。在请求期间访问安全方法将失败。

  • method HTTP方法将使用与模式匹配传入的请求合并。若是省略,任何方法将匹配。若是一个相同的模式被指定,而没有一个方法,该方法特定的匹配将优先。

  • pattern 定义了网址路径的模式。内容将取决于 request-matcher 从包含HTTP元素属性,因此将默认的Ant路径语法。

  • requires-channel “http”或“https”取决于一个特定的URL模式应该访问的HTTP或HTTPS区别。 lternatively值“any”能够用来当没有偏好。若是这个属性是存在于any <intercept-url> 元, 而后一个 ChannelProcessingFilter 将添加到筛选器堆栈中,并将其添加到应用程序上下文中的附加依赖项添加到。

若是一个 <port-mappings> 配置添加,他将被用于 SecureChannelProcessor 和 InsecureChannelProcessor beans 用来重定向到 HTTP/HTTPS端口.

<jee>

添加到过滤器链j2eepreauthenticatedprocessingfilter提供集成容器认证。

父元素 <jee>
<jee> 属性
  • mappable-roles 逗号隔开要查询传入的HttpServletRequest消息的角色列表。

  • user-service-ref 对用户的服务(或userdetailsservice bean)ID

<logout>

添加一个LogoutFilter 到过滤器堆栈。这是配置一个 SecurityContextLogoutHandler

父元素 <logout>
<logout> 属性
  • delete-cookies 当用户登陆时,应删除的一个逗号分隔的名称列表。

  • invalidate-session 映射一个invalidateHttpSession的 SecurityContextLogoutHandler. 默认值为“真”,因此,会话将被做废注销。

  • logout-success-url 登陆后用户将采起目标网址。默认值为 <form-login-login-page>/?logout (i.e. /login?logout)

    设置此属性将注入SessionManagementFilter 和一个SimpleRedirectInvalidSessionStrategy配置属性值。当一个无效的会话ID提交,该战略将调用重定向到配置的URL。

  • logout-url URL会形成注销 (i.e. 将由过滤器处理). 默认值为 "/logout".

  • success-handler-ref 可用于提供一个实例 LogoutSuccessHandler 将被调用来控制日志记录后的导航。

<openid-login>

相似于<form-login>,而且具备相同的属性. login-processing-url的默认值是"/login/openid".OpenIDAuthenticationFilter和 OpenIDAuthenticationProvider 将被注册. 后者须要去引用一个 UserDetailsService. 一样, 这样能够被 id指定, 使用 user-service-ref 属性, 或者将在应用程序上下文中被自动定位。

<openid-login>的父元素
<openid-login>的属性
  • Always-use-the-default-target 用户应该老是被重定向到登陆后的默认目标网址.

  • authentication-details-source-ref 对将要使用身份验证过滤引用一个身份验证详细信息源

  • authentication-failure-handler-ref 引用一个AuthenticationFailureHandler bean,应用于处理身份验证失败的请求.不该该使用与身份验证失败的连接组合,实施执行处理导航到后续的目标.

  • authentication-failure-url 登陆失败页面的网址.若是没有指定登陆失败的网址, Spring Security 将自动建立一个失败的登陆网址,当请求登陆失败的网址时会开出登陆错误和一个相应的过滤器.

  • authentication-success-forward-url 在UsernamePasswordAuthenticationFilter属性中将 ForwardAuthenticationSuccessHandler 映射到 authenticationSuccessHandler .

  • authentication-failure-forward-url 在UsernamePasswordAuthenticationFilter属性中将 ForwardAuthenticationSuccessHandler 映射到 authenticationSuccessHandler .

  • authentication-success-handler-ref 引用一个AuthenticationSuccessHandler bean应用于处理一个成功的身份验证请求.不该与组合使用. default-target-url (or always-use-default-target) 实现执行是处理导航到后续的目标.

  • default-target-url 若是用户的前一个动做没法恢复,将被重定向到成功认证后的URL.一般若是用户访问登陆页面没有首先要求安全操做,将会触发身份验证.若是未指定,默认为应用程序的根.

  • login-page 登陆页面URL. 若是没有指定登陆的URL, Spring Security将自动建立一个登陆网址和一个相应的过滤器,以呈现被请求的登陆网址.

  • login-processing-url 登陆窗口被发布的网址.若是未被指定,它默认为登陆.

  • password-parameter 包含密码的请求参数的名称。默认为"password".

  • user-service-ref 参考用户服务(或用户详细信息服务)Id

  • username-parameter 包含用户名的请求参数的名称。默认为 "username".

<openid-login>的子元素

<attribute-exchange>

attribute-exchange元素定义属性列表应该从身份提供程序中请求. 在OpenID Support 命名空间配置章节的部分能够找出一个例子. 不仅一个能够使用, 在这种状况下每一个必须有 identifier-match 属性, 对所提供的OpenID标识符匹配包含一个正则表达式. 这容许从不一样的供应商(Google, Yahoo etc)获取不一样的属性列表 .

<attribute-exchange>的父元素
<attribute-exchange>属性
  • identifier-match 当决定在身份验证过程当中使用哪些属性交换配置,将要与所请求的标识进行比较的正则表达式.

<attribute-exchange>的子元素

<openid-attribute>

用于制造一个OpenID Ax属性 Fetch Request

<openid-attribute>的父元素
<openid-attribute> 属性
  • count 指定要返回的属性的数量。例如,返回3个电子邮件. 默认值是 1.

  • name 指定要返回的属性的名称。例如,电子邮件.

  • required 指定此属性是否被要求对操做,但若是操做不返回属性,则不出错。默认为false.

<port-mappings>

默认状况下,实例portmapperimpl将被添加到配置中用于安全和不安全的URL重定向到.此元素能够选择地用于重写该类定义的默认映射. 每一个 <port-mapping> 元素定义了一对 HTTP:HTTPS 端口. 默认的映射是80:443和8080:8443.重写这些的例子能够在 namespace introduction找到.

<port-mappings>的父元素
<port-mappings>的子元素

<port-mappings>

当强制重定向提供了一个地图的HTTP端口HTTPS端口方式.

<port-mappings>父元素
<port-mappings> 属性
  • http HTTP端口使用.

  • https HTTPS端口使用.

<remember-me>

添加 RememberMeAuthenticationFilter到堆栈.根据属性设置,将依次配置一个 TokenBasedRememberMeServices,一个PersistentTokenBasedRememberMeServices 或用户指定实现 RememberMeServices .

<remember-me>的父元素
<remember-me> 属性
  • authentication-success-handler-ref 若是须要自定义导航,在RememberMeAuthenticationFilter上设置authenticationSuccessHandler.在应用程序上下文中该值应该是个` authenticationsuccesshandler ` bean的名称.

  • data-source-ref 引用一个 DataSource bean. 若是这样设置,persistenttokenbasedremembermeservices `将使用和配置一个 jdbctokenrepositoryimpl `实例.

  • remember-me-parameter 切换 remember-me认证请求的参数名.默认为"remember-me". 映射到"parameter"的AbstractRememberMeServices属性.

  • key AbstractRememberMeServices属性映射到"key" . ,以确保remember-me cookies 仅在一个应用程序脚注中有效:[这不影响使用 PersistentTokenBasedRememberMeServices, 令牌存储在服务器端.]. 若是这不是设置一个将产生的安全的随机值. 由于生成安全的随机值可能须要一段时间, 当咱们使用remember me功能时,设置一个明确的值能够改善启动时间.

  • services-alias 输出内部定义的 RememberMeServices 做为 bean 别名,容许它在应用程序上下文中被其它beans使用.

  • services-ref 将被使用的过滤器容许` remembermeservices 彻底控制实施. 值应该是在应用程序上下文中实现此接口的bean的"id". 若是注销过滤器在使用也应该执行 logouthandler `.

  • token-repository-ref 配置一个 PersistentTokenBasedRememberMeServices 可是容许使用一个自定义的 PersistentTokenRepository bean.

  • token-validity-seconds AbstractRememberMeServices属性映射到 tokenValiditySeconds . 指定remember-me cookie在几秒钟内应是有效的. 默认状况下,有效期为14天.

<request-cache> 元素

集将被 ExceptionTranslationFilter使用的 RequestCache实例去存储在调用AuthenticationEntryPoint前的请求信息.

<request-cache>父元素
<request-cache> 属性
  • ref 对Spring bean定义一个引用,它是一个 RequestCache.

<session-management>

经过添加一个 SessionManagementFilter 到过滤器栈,Session-management 相关功能时被实施的.

<session-management>父元素
<session-management> 属性
  • invalid-session-url 设置此属性将会注入 SessionManagementFilter 一个 SimpleRedirectInvalidSessionStrategy 配置属性值.当提交一个无效的ID, 该战略将会被调用到重定向配置的URL.

  • session-authentication-error-url 定义的错误页面应该显示在sessionauthenticationstrategy引起异常的URL. 若是没有设置,未经受权的(401)错误代码将返回到客户端. 请注意,若是错误发生在一个基于窗体的登陆,此属性不适用.在身份验证失败的网址将优先.

  • session-authentication-strategy-ref 容许加入被 SessionManagementFilter使用的SessionAuthenticationStrategy 实例.

  • session-fixation-protection 说明会话固定保护的应用将在用户认证. 若是设置为"none", 将不会应用保护. "newSession" 将新建一个新的空会话, 只有Spring Security相关属性迁移. "migrateSession" 将建立一个新的会话,并将全部会话属性复制到新会话中. In Servlet 3.1 (Java EE 7) 新的容器, 指定“changesessionid”将保持现有的会话和使用容器提供的会话固定保护(HttpServletRequest # changesessionid()).默认为“changesessionid在Servlet 3.1和新的容器, “migratesession”在大容器.若是“changesessionid”用于大容器,抛出一个异常.

    若是启用会话固定保护, ` sessionmanagementfilter 注入一个适当的配置 defaultsessionauthenticationstrategy `.看到这类Javadoc详情.

<session-management>子元素

<concurrency-control>

添加支持并发会话控制, 容许将限制放置在用户能够拥有的活动会话的数量上. 一个` concurrentsessionfilter 将被建立, 而且一个 `ConcurrentSessionControlAuthenticationStrategy 将会可用于 SessionManagementFilter. 若是已声明 form-login元素,则该策略对象也将被注入到所建立的验证筛选器中.一个 SessionRegistry(一个除非用户但愿使用一个自定义bean的SessionRegistryImpl实例)将被建立供使用的战略实例.

<concurrency-control>父元素
<concurrency-control>属性
  • error-if-maximum-exceeded 若是设置为"true",当用户试图超过容许的最大会话数时,SessionAuthenticationException将会被引起. 这默认的行为是使一个原始的会话失效.

  • expired-url 若是他们试图使用一个已被并发会话控制器"expired"的会话,URL用户将被重定向,由于用户已经超过了容许的会话数,并在其余地方再次登陆. 除非 exception-if-maximum-exceeded被设置.若是没有提供任何值,一个有效消息将直接返回到响应.

  • max-sessions ConcurrentSessionControlAuthenticationStrategy属性映射到maximumSessions.

  • session-registry-alias 他也能够是有用的,对内部会话注册表有一个参考,用于在你本身的beans或管理接口. 使用 session-registry-alias属性,能够使内部bean公开, 给它一个名称,你能够在你的配置中的其余地方使用.

  • session-registry-ref 用户能够提供本身的` sessionregistry 实现使用`session-registry-ref 属性. 其余并发会话控制beans将被链接起来使用它.

<x509>

增长了支持X.509认证. 一个 X509AuthenticationFilter 将被添加到堆栈和 Http403ForbiddenEntryPoint bean 被建立. 后者只会在没有其余认证机制的时候使用(它惟一的功能是返回一个HTTP 403错误代码). ` preauthenticatedauthenticationprovider`也将建立一个将用户权限加载到一个` userdetailsservice `的地方中.

<x509>父元素
<x509> 属性
  • authentication-details-source-ref 引用一个 AuthenticationDetailsSource

  • subject-principal-regex 定义一个正则表达式,该表达式将用于从证书中提取用户名 (用于使用 UserDetailsService).

  • user-service-ref 容许使用特定的 `UserDetailsService`X.509的状况下配置多个实例.若是没有设置,将试图自动找到一个合适的实例,并使用.

<filter-chain-map>

用于显式配置filterchainproxy与filterchainmap实例

<filter-chain-map> 属性
  • request-matcher 定义策略用于匹配传入请求的使用. 目前的选项是'ant'(蚂蚁路径模式), 'regex'正则表达式和'ciRegex' 不区分大小写的正则表达式.

<filter-chain-map>子元素

<filter-chain>

用于定义一个特定的URL模式和适用于该模式匹配的URL的过滤器列表.当多个filter-chain元素组合在一个列表中为了配置FilterChainProxy,最具体的模式必须放在列表的顶部,在底部最通常的模式.

<filter-chain>父元素
<filter-chain> 属性
  • filters 一个逗号分隔的列表引用Spring bean实现 Filter. 值"none"意味着没有 Filter应该用于` FilterChain `.

  • request-matcher-ref 引用一个` requestmatcher 将用于肯定是否有一些`Filter来自 filters应该被调用的属性.

<filter-security-metadata-source>

用于显式配置FilterSecurityMetadataSource FilterSecurityInterceptor bean使用. 若是你正在配置FilterChainProxy,只须要明确的这一个,而不是使用<http>元素.截取只包含方法和访问属性模式的intercept-url.任何其余的将致使配置错误.

<filter-security-metadata-source> 属性
  • id 一个bean标识符, 用于指在上下文中的其余地方的bean.

  • lowercase-comparisons 比较后迫使小写

  • request-matcher 定义用于匹配传入请求的策略.目前的选择是 'ant'(蚂蚁路径模式), 'regex' 正则表达式和'ciRegex' 不区分大小写的正则表达式.

  • use-expressions 能够使用在<intercept-url>元素中表达式'access'的属性,而不是传统的配置属性的列表.默认为 'true'.若是启用,每一个属性应该包含一个单一的布尔表达式. 若是表达式计算结果为'true',则访问将被授予.

<filter-security-metadata-source>子元素

WebSocket 安全

Spring Security 4.0+为受权消息提供支持.这是一个为WebSocket基础应用程序提供受权有用的例子.

<websocket-message-broker>

websocket-message-broker元素有两种不一样的模式. 若是websocket-message-broker@id 没有指定,那么它会作如下事情:

  • 确保任何SimpAnnotationMethodMessageHandler AuthenticationPrincipalArgumentResolver注册做为一个自定义参数解析器. 这容许使用 @AuthenticationPrincipal 来解决当前的主要Authentication

  • 确保securitycontextchannelinterceptor自动注册为clientinboundchannel. 这与用户填充SecurityContextHolder消息中被发现.

  • 确保channelsecurityinterceptor与clientinboundchannel注册. 这容许受权规则指定的消息.

  • 确保CsrfChannelInterceptor与clientInboundChannel注册.这将确保只有从原来的域的请求被启用. *确保CsrfTokenHandshakeInterceptor与WebSocketHttpRequestHandler, TransportHandlingSockJsService,或DefaultSockJsService注册.这保证了预期的csrftoken来自消息复制到WebSocket Session属性.

若是额外的控制是必要的,能够指定ID和channelsecurityinterceptor将分配给指定的ID. 全部的布线与Spring的消息传递基础设施能够手动完成的.这是比较麻烦的,但提供了更大的配置控制.

<websocket-message-broker>属性
  • id 一个bean的标识符,用于指在channelsecurityinterceptor bean的上下文中的任何地方. 若是指定,Spring Security须要在Spring Messaging内明确的配置. 若是没有指定,Spring Security会自动整合与通信基础设施,如<websocket-message-broker>描述的.

  • same-origin-disabled 禁用要求CSRF令牌出如今Stomp headers(默认错误). 若是有必要让其余起源SockJS链接,更改默认是有用的.

<websocket-message-broker>子元素

<intercept-message>

定义消息的受权规则.

<intercept-message>父元素
<intercept-message> 属性
  • pattern 一种目的基于匹配Message的蚁群模式.例如, "/" matches any Message with a destination; "/admin/" 匹配任何有一个以"/admin/**"开头为目的地的Message".

  • type 要匹配的消息的类型. 在simpmessagetype有效值的定义 (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER).

  • access 用于保护信息的表达式.例如,"DenyAll"将拒绝访问全部的匹配信息;"permitall"将授予访问全部的匹配信息;"hasrole('admin')"须要当前用户拥有的角色"role_admin"匹配的信息.

认证服务

在Spring Security 3.0以前, AuthenticationManager 在内部是自动注册的. 如今,你必须使用 <authentication-manager> 元素明确的注册一个. 这将建立Spring Security的 ProviderManager类的一个实例, 须要配置一个或多个` AuthenticationProvider 实例. 这些均可以使用命名空间提供的语法元素来建立, 也能够是标准的bean定义, 标记为除了使用 `authentication-provider元素的列表.

<authentication-manager>

每一个Spring Security应用程序使用名称空间必须包括这个元素.它负责注册的` authenticationManager 为应用提供认证服务. 全部元素的建立 AuthenticationProvider `实例应该是这个子元素.

<authentication-manager> 属性
  • alias 此属性容许你为你本身的配置中使用的内部实例定义别名. 它的用途是描述在namespace introduction.

  • erase-credentials 若是设置为真, AuthenticationManager将试图清除任何凭据数据在返回的验证对象中, 一旦用户已被身份验证.实际上它映射到eraseCredentialsAfterAuthentication属性的 ProviderManager. 这是在 Core Services 章节中讨论的.

  • id 此属性容许你为内部实例定义一个用于在本身的配置中使用的标识. 它是相同的别名元素, 但提供了一个更加一致的经验使用id属性的元素.

<authentication-manager>子元素

<authentication-provider>

除非用` REF 属性, 这个元素是缩写配置一个 DaoAuthenticationProvider. `DaoAuthenticationProvider 加载用户信息从一个` userdetailsservice 和用户名/密码组合所提供的登陆时比较. ` userdetailsservice `实例能够经过使用可用的命名空间元素定义 ( `jdbc-user-service 或者经过使用 user-service-ref 属性指向一个bean定义在应用程序上下文). 在 namespace introduction中你能够找到这些变化的例子.

<authentication-provider>父元素
<authentication-provider> 属性
  • ref 定义引用一个Spring bean实现AuthenticationProvider.

若是你写了本身的 AuthenticationProvider实现(或者想配置一个Spring Security的实现做为一个传统的bean,而后,你能够使用下面的语法将它添加到` providermanager ` 内部列表:

<security:authentication-manager>
<security:authentication-provider ref="myAuthenticationProvider" />
</security:authentication-manager>
<bean id="myAuthenticationProvider" class="com.something.MyAuthenticationProvider"/>
  • user-service-ref 引用bean实现UserDetailsService能够建立使用标准的bean元素或自定义 ser-service 元素.

<jdbc-user-service>

建立一个JDBC-based UserDetailsService.

<jdbc-user-service> 属性
  • authorities-by-username-query 一个SQL语句查询用户授予政府给定的用户名.

默认为

select username, authority from authorities where username = ?
  • cache-ref 定义引用UserDetailsService缓存.

  • data-source-ref bean ID 提供所需的表的数据源.

  • group-authorities-by-username-query 一条SQL语句来查询用户组部门给定的用户名.

默认为

+

select
g.id, g.group_name, ga.authority
from
groups g, group_members gm, group_authorities ga
where
gm.username = ? and g.id = ga.group_id and g.id = gm.group_id
  • id bean标识符, 用于bean在上下文的任何地方.

  • role-prefix 从永久存储(默认是 "ROLE_")中,一个非空字符串前缀字符串将被添加到角色加载.在默认为非空的状况下,使用没有前缀的值"none".

  • users-by-username-query 一个SQL语句查询用户名、密码,并启用了一个用户名状态. 默认为

    select username, password, enabled from users where username = ?

<password-encoder>

namespace introduction所描述的,身份验证提供者能够被配置为使用一个密码编码器. 这将致使bean注入到相应的` passwordencoder 实例中, 可能可能伴随 `SaltSource bean提供盐散列值.

<password-encoder>父元素
<password-encoder>属性
  • base64 一个字符串是否应该被Base64编码

  • hash 定义用于用户密码的散列算法.咱们强烈建议你不要使用MD4,由于它是一个很是弱的散列算法.

  • ref 定义引用一个Spring bean 实现PasswordEncoder.

<password-encoder>子元素

<salt-source>

口令保护策略. 能够使用来自UserDetails对象的系统常数和属性.

<salt-source>父元素
<salt-source>属性
  • ref 定义引用一个Spring bean Id.

  • system-wide 一个单一的值,将被用来做为一个密码编码器的salt.

  • user-property UserDetails对象的属性将被用做salt经过密码编码器. 一般状况下,像"username"可能会被使用.

<user-service>

从属性文件或列表中的"user"子元素建立一个UserDetailsService内存. 内部转换为小写,容许用户名不区分大小写的查询,因此这个不该使用是否须要区分大小写.

<user-service> 属性
  • id bean标识符,用于指bean在上下文的任何地方.

  • properties 其中属性文件的位置,每一行的格式为

    username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]
<user-service>子元素

<user>

表示应用程序中的用户.

<user>父元素
<user> 属性
  • authorities 一个或多个authorities授予的用户. 用逗号隔开authorities (但没有空间).例如, "ROLE_USER,ROLE_ADMINISTRATOR"

  • disabled 能够设置为"true"来标记一个账户禁用,没法使用.

  • locked 能够设置为"true"来标记一个账户锁定,没法使用.

  • name 分配给用户的用户名.

  • password 分配给用户的密码. 若是相应的认证供应商支持哈希(记得设置"user-service"的 "hash"属性元素),这多是散列.此属性被省略的状况下,该数据将不会被用于身份验证.但仅用于访问authorities.若是省略,命名空间将生成一个随机值,防止其意外使用身份验证。不能为空.

方法安全性

<global-method-security>

这个元素的主要手段是在Spring Security beans中添加支持安全方法.能够经过使用注释担保(在接口或类定义)或经过定义一组的切入点做为子元素的方法,使用AspectJ语法.

<global-method-security> 属性
  • access-decision-manager-ref 使用与AccessDecisionManager相同的安全方法配置网络安全, 但这能够使用此属性覆盖.默认状况下AffirmativeBased实现用于RoleVoter和AuthenticatedVoter.

  • authentication-manager-ref 引用一个 AuthenticationManager ,应该用于方法安全性.

  • jsr250-annotations 指定是否使用JSR-250样式属性(例如"RolesAllowed"). 这将须要javax.annotation.安全类在类路径中.将此设置为真也增长一个 Jsr250VoterAccessDecisionManager,因此你须要确保你这样作,若是你正在使用一个自定义的实现和想要使用这些注释.

  • metadata-source-ref 外部methodsecuritymetadatasource实例能够提供优先于其余来源(如默认的注释).

  • mode 该属性能够设置为"AspectJ"指定AspectJ应该用来代替默认的Spring AOP. 方法安全性必须被来自spring-security-aspects组件AnnotationSecurityAspect编排.

须要注意的是AspectJ遵循Java接口上的注释不是继承的.这意味着定义接口的Security annotaitons方法将是不安全的. 相反, 当在使用AspectJ时,你必须把Security annotation放在类上.

  • order 容许建议"order"将被设置为方法安全拦截.

  • pre-post-annotations 指定是否使用Spring Security的先后调用注释 (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) 应该支持这个应用程序上下文。默认为"disabled".

  • proxy-target-class 若是这是真的,将使用基于类的代理,而不是基于接口的代理.

  • run-as-manager-ref 引用一个可选的RunAsManager实现可经过配置的MethodSecurityInterceptor

  • secured-annotations 指定是否使用Spring Security的 @Secured annotations 启用应用程序上下文. 默认为 "disabled".