授权
在Spring Security的高级授权功能是其受欢迎的最有说服力的原因之一,无论您如何选择如何进行身份验证-是否使用提供的机制和提供程序的Spring Security,或整合与一个容器或其他non-Spring Security 认证机构-你会发现授权服务可以在您的应用程序中使用一个一致的和简单的方式.
在这一部分我们将探讨不同的` abstractsecurityinterceptor `实现,在第一部分介绍.然后,我们将继续探索如何通过使用域访问控制列表微调授权.
授权体系结构
授权
正如我们在<<技术授予权,技术综述 >>所看到,所有的Authentication
实现存储的列表GrantedAuthority
对象.这些代表已被授予主要的的当局. GrantedAuthority
对象是由` authenticationManager 插入到`Authentication
对象,然后读取 AccessDecisionManager
做出判断.
GrantedAuthority
是一个只有一个方法的接口
String getAuthority();
这个方法允许AccessDecisionManager
来判断得到一个精确的String
表示的` GrantedAuthority .通过返回一个表示作为一个`String
,一个` GrantedAuthority 可以很容易的通过`AccessDecisionManager
来read
,如果一个` GrantedAuthority 不能精确地表示为一个`String
,` GrantedAuthority 将会被认为是"complex"和`getAuthority()
必须返回为null
.
"complex" GrantedAuthority
的一个将一个应用于不同客户帐户号码的操作和权限阈值的列表的实现例子.代表这个复杂的` GrantedAuthority 作为`String
将是相当困难的,作为一个结果,` getauthority() 方法应该返回`null
.这将对任何` accessDecisionManager 表明它需要明确的支持
GrantedAuthority `实施以了解其内容.
Spring Security包括一个具体的` GrantedAuthority 实施,
grantedauthorityimpl .这允许用户指定的任何String
转换成一种` GrantedAuthority .所有的
AuthenticationProvider 的包括与安全架构使用
grantedauthorityimpl`填充Authentication
对象.
Pre-Invocation处理
正如我们在<<安全对象、技术综述>>章节中也看到过的,Spring Security,提供拦截控制访问安全对象如方法调用或Web请求。是否允许进行调用前调用的决定是由`AccessDecisionManager `作出判断.
访问决策管理器
` accessDecisionManager 被
abstractsecurityinterceptor 和负责制定最终的访问控制决策.`AccessDecisionManager
接口包含三种方法:
void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
AccessDecisionManager
的decide
方法传递了它所需要的所有相关信息,以作出授权决策.尤其,通过安全的“对象”,使这些参数包含在实际的安全对象调用中进行检查.例如,让我们假设安全对象是一个MethodInvocation `资料,这将是很容易实现`MethodInvocation
对于任何Customer
论点.然后执行某种安全逻辑判断、来确保AccessDecisionManager `主允许对客户操作.如果访问被拒绝并抛出`AccessDeniedException
我们的预期就实现了.
如果` accessDecisionManager 可以处理通过
configattribute ,`supports(ConfigAttribute)
方法由AbstractSecurityInterceptor
在决定启动时候命名. supports(Class)
方法被安全拦截器实现,确保配置` accessDecisionManager `支持类型的安全对象的被拦截.
Voting-Based访问决策管理器实现
同时,用户可以实现自己的` AccessDecisionManager`判断、控制授权的所有方面,Spring Security包括几个基于投票的` accessDecisionManager `实现. 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
以及这个具体实现.
像Spring Security的其他部分,AfterInvocationManager
有一个具体的实现,AfterInvocationProviderManager
调查AfterInvocationProvider
的表,每一个AfterInvocationProvider
允许修改返回对象或抛出AccessDeniedException
.的确多个提供者可以修改对象,如之前的供应商的结果传递给下一个列表中.
请注意,如果您正在使用AfterInvocationManager
,你仍然需要配置属性,使MethodSecurityInterceptor
的AccessDecisionManager
允许一个操作.如果您使用的是典型的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 `.这提供了一些常见的表达式,可应用在网络和方法安全性.
表达 | 描述 |
---|---|
| 如果当前主体具有指定的角色,则返回 |
| 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回 |
| 如果当前的主体具有指定的权限,则返回 |
| 如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回 |
| 允许直接访问表示当前用户的主对象 |
| 允许直接访问从 |
| 总是评估为 |
| 总是评估为 |
| 如果当前的主体是一个匿名用户,则返回 |
| 如果当前的主体是一个匿名用户,则返回 |
| 如果用户不是匿名的,则返回 |
| 如果用户不是一个匿名的或是一个记住我的用户返回 |
| 如果用户已访问给定权限的提供的目标,则返回 |
| 如果用户已访问给定权限的提供的目标,则返回 |
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的方法.
@PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);
我们访问另一个内置的表情, authentication
,也就是 Authentication
存储在安全上下文。您也可以直接访问它的principal
属性,使用表达式principal
。值往往会是一个“UserDetails”实例,所以你可能会使用一个表达式principal.username
或“principal.enabled”.
过滤用@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
然后注入JdbcMutableAclService
和BasicLookupStrategy
实例。后者提供高性能的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信息作为授权决策逻辑的一部分。这里有许多选择。您可以编写自己的AccessDecisionVoter
或AfterInvocationProvider
分别触发一个方法调用之前或之后。这些课程将使用AclService
来检索相关的ACL,然后调用的ACL。i`Acl.isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)决定是否授予或拒绝许可。或者,您可以使用我们的`AclEntryVoter
, AclEntryAfterInvocationProvider
或 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.securedUIPrefix
和spring.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`的实例,所以他们支持任何格式工厂,他们不一定是整数,字符串可以像READ
或WRITE
.如果没有找到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
实现的基础.子类必须实现方法,创建了LoginContext
. AbstractJaasAuthenticationProvider
有许多依赖关系,下面讨论它
JAAS回调处理程序
大多数JAAS LoginModule
的年代需要一个回调。这些回调通常用于获得用户的用户名和密码.
在Spring Security部署中,Spring Security负责这个用户交互(通过身份验证机制),因此,当委托到JAAS身份验证请求,Spring安全的身份验证机制已经完全填充一个身份验证的对象包含所有所需的JAAS LoginModule的信息.
因此,为Spring Security JAAS包提供了两个默认回调处理程序,JaasNameCallbackHandler
和JaasPasswordCallbackHandler
.每一个回调处理程序实现JaasAuthenticationCallbackHandler
.在大多数情况下,这些回调处理程序可以简单地使用不了解内部力学.
对于那些需要完全控制回调行为,内部AbstractJaasAuthenticationProvider
用InternalCallbackHandler
包装这些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配置文件.它在文中 DefaultJaasAuthenticationProvider
比JaasAuthenticationProvider
更灵活,因为它不依赖默认配置的实现.
使用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服务器,您还需要指定一个AuthenticationHandler
在deployerConfigContext.xml
包含ca。AuthenticationHandler
有一个简单的方法,该方法返回一个布尔判断是否一个给定的证书是有效的.你AuthenticationHandler
的实现需要链接到某种类型的后端身份验证存储库,如LDAP服务器或数据库,CAS本身包含许多AuthenticationHandler
的协助.当你下载服务器和部署war文件时,它被设置为成功进行身份验证的用户输入一个密码匹配他们的用户名,用于测试.
Spring Security和CAS交互序列
基本的web浏览器之间的交互,CAS服务器和春天Security-secured服务如下:
-
web用户浏览服务的公共页面.CAS或Spring Security不参与。
-
最终用户请求一个页面或者安全bean的使用是安全的。Spring Security的ExceptionTranslationFilter将检测到
AccessDeniedException
或AuthenticationException
. -
因为用户的
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
,这是依次配置了CasAuthenticationProvider
.CasAuthenticationProvider
只响应包含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。它将返回到CasAuthenticationProvider
的TicketResponse
,其中包括用户名(强制),代理列表(如果有涉及),和proxy-granting票借据(如果请求代理回调)。 -
接下来的
CasAuthenticationProvider
将称之为CasProxyDecider
配置.CasProxyDecider
表明代理列表中TicketResponse
是否接受服务。几个实现提供SpringSecurity:`RejectProxyTickets`,AcceptAnyCasProxy
和NamedCasProxyDecider
。这些名字在很大程度上是自解释的,除了NamedCasProxyDecider
允许List
提供可信的代理。 -
CasAuthenticationProvider
将下一个请求的AuthenticationUserDetailsService
加载GrantedAuthority
对象,适用于用户包含在Assertion
. -
如果没有问题,
CasAuthenticationProvider
构造CasAuthenticationToken包括细节包含在TicketResponse
和GrantedAuthority
. -
控制然后返回
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
替换为一个Cas20ProxyTicketValidator
. proxyCallbackUrl
应该设置为一个应用程序将接收页面表的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
接受页面表和存储。重要的是proxyReceptorUrl
与proxyCallbackUrl
匹配的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 application在ProxyTicketSampleServlet
包含一个工作示例。可以找到示例代码如下:
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
的区分有状态的和无状态的客户。一个有状态的客户被认为是提交CasAuthenticationFilter
的filterProcessUrl
.无状态的客户的任何一个身份验证请求CasAuthenticationFilter
比filterProcessUrl
另一个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>
下一步是指定serviceProperties
和authenticationDetailsSource
和CasAuthenticationFilter
。“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
对象在SecurityContext
和SecurityContextHolder
安全对象回调阶段。这只发生如果最初的Authentication
对象是成功处理的AuthenticationManager
和AccessDecisionManager
.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
,散列键存储在所有生成的令牌. RunAsManagerImpl
和RunAsImplAuthenticationProvider
中创建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
创建一个线程。 -
自从创建了
DelegatingSecurityContextRunnable
和SecurityContext
从SecurityContextHolder
这里有一个快捷方式的构造函数,下面的代码与前面的代码相同:
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规则匹配用于处理您的请求的逻辑.
它总是建议提供授权规则匹配的 通过匹配提供授权规则 |
考虑一个控制器映射如下:
@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 结合 |
没有一个自动集成与 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 实施.
-
acl_sid
Store身份确认和安全通过ALC系统来保障, 这些可以适用于唯一的或者多个负责人。 -
acl_class
定义域的对象类型的ACL应用。class
列储存java类对象名称。 -
acl_object_identity
储存的具体领域对象的标识的定义. -
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 在命名空间介绍中,删除一个与以前版本的框架的常见错误源,当用户在该框架中明确地配置了过滤器链时 FilterChainProxy
bean.如果你需要完全控制配置的话,你仍然可以这样做。
所需要参考所有过滤器 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匹配传入的请求。 选择目前mvc
,ant
,regex
和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
.
-
use-expressions 使能在
access
属性,如章节所述 expression-based access-control 默认值为真。
<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-Control
,Pragma
,和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
orPublic-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-Control
, Pragma
, 和 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>
<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-disabled 不包括标题 reflected / Type-1 Cross-Site Scripting (XSS)的保护。
-
xss-protection-enabled 明确使用eisable reflected / Type-1 Cross-Site Scripting (XSS) 的保护。
-
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 使用默认的命名空间设置,匿名“身份验证”设施将自动启用。您可以使用此属性禁用它。
-
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 映射到
ForwardAuthenticationSuccessHandler
authenticationSuccessHandler
特性UsernamePasswordAuthenticationFilter
。
-
authentication-failure-forward-url 映射到
ForwardAuthenticationFailureHandler
authenticationFailureHandler
特性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> 属性
-
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.
-
type 指定属性类型。例如, http://axschema.org/contact/email. 查看你的操作的有效属性类型的文档.
<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 `.
-
pattern A-pattern创造结合RequestMatcher request-matcher
-
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 元素.
<authentication-provider>子元素
<jdbc-user-service>
创建一个JDBC-based UserDetailsService.
<jdbc-user-service> 属性
默认为
select username, authority from authorities where username = ?
-
cache-ref 定义引用UserDetailsService缓存.
-
data-source-ref bean ID 提供所需的表的数据源.
默认为
+
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> 属性
-
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.安全类在类路径中.将此设置为真也增加一个
Jsr250Voter
到AccessDecisionManager
,所以你需要确保你这样做,如果你正在使用一个自定义的实现和想要使用这些注释.
-
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".
<global-method-security>子元素
<after-invocation-provider>
通过 <global-method-security>
的命名空间,这个元素可以用来装饰一个 AfterInvocationProvider
用于维护的安全拦截器.你可以定义零个或多个 global-method-security
内的元素,在应用程序上下文中,每一个都有 ref
属性指向一个 AfterInvocationProvider
bean实例.
<after-invocation-provider>父元素
<after-invocation-provider> 属性
-
ref 定义引用一个Spring bean 实现
AfterInvocationProvider
.
<pre-post-annotation-handling>
允许默认表达式的机制来处理Spring Security的前后调用注释 (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) 去完全取代. 仅适用于这些被启用了的注释.
<pre-post-annotation-handling>父元素
<pre-post-annotation-handling>子元素
<invocation-attribute-factory>
定义了PrePostInvocationAttributeFactory实例用于生成前后调用元数据注释的方法.
<invocation-attribute-factory>父元素
<invocation-attribute-factory> 属性
-
ref 定义引用一个 Spring bean Id.
<post-invocation-advice>
对于<pre-post-annotation-handling> 元素,定制 PostInvocationAdviceProvider
编号为 PostInvocationAuthorizationAdvice
.
<post-invocation-advice>父元素
<post-invocation-advice> 属性
-
ref 定义引用一个Spring bean Id.
<pre-invocation-advice>
对于<pre-post-annotation-handling>元素,定制 PreInvocationAuthorizationAdviceVoter
编号为 PreInvocationAuthorizationAdviceVoter
.
<pre-invocation-advice>父元素
<pre-invocation-advice>属性
-
ref 定义引用一个Spring bean Id.
方法安全性的使用
<protect-pointcut>
而不是定义一个单独的方法或类基础的安全属性使用 @Secured
注释, 你可以跨整个定义横切安全约束集的方法和接口服务层中使用 <protect-pointcut>
元素.你可以在 namespace introduction中找到一个例子.
<protect-pointcut>父元素
<protect-pointcut> 属性
-
access 访问适用于所有的匹配方法的切入点的配置属性列表, 例如. "ROLE_A,ROLE_B"
-
expression 一个AspectJ的表达式, 包括'execution'关键字. 例如, 'execution(int com.foo.TargetObject.countLength(String))' (没有引号).
<intercept-methods>
可以使用在bean内的定义去添加一个安全拦截器到bean可以使用在bean定义安全拦截器添加到bean并,设置访问bean的配置属性的方法.
<intercept-methods> 属性
-
access-decision-manager-ref 可选AccessDecisionManager bean ID创建的方法安全性拦截器使用.
<intercept-methods>子元素
<method-security-metadata-source>
创建一个MethodSecurityMetadataSource 实例
<method-security-metadata-source>属性
-
id bean标识符, 用于指向bean的上下文中.
-
use-expressions 可以使用 <intercept-url>元素 'access'属性表达式,而不是传统的配置属性列表. 默认为 'false'. 如果启用了, 每个属性应该包含一个boolean表达式. 如果表达式计算结果为'true', 访问将被授予.
<method-security-metadata-source>子元素
<protect>
定义一个应用于它的受保护方法和访问控制配置属性. 我们强烈建议你不要将"protect"申明与提供的"global-method-security"的任何服务混合在一起.
<protect>父元素
<protect> 属性
-
access 一种适用于该方法的访问配置属性列表,例如. "ROLE_A,ROLE_B".
-
method 方法名称
LDAP命名空间选项
LDAP是覆盖一些细节在its own chapter. 我们将扩大在一些解释的名称空间映射到Spring bean的选项.LDAP 广泛的实现使用Spring LDAP,因此,一些熟悉该项目的API可能是有用的.
定义LDAP服务器使用
<ldap-server>
元素 该元素设置了一个 Spring LDAP ContextSource
用于其他 LDAP beans, 定义LDAP服务器的位置和其他信息(如用户名和密码,如果它不允许匿名访问) 用于连接到它.它也可以被用来创建一个嵌入式服务器进行测试. 两个选项的语法的细节是在 LDAP chapter. 实际的 ContextSource
实施是 DefaultSpringSecurityContextSource
延伸 Spring LDAP的 LdapContextSource
类. manager-dn
和 manager-password
属性映射到后面的 userDn
和 password
属性分别.
如果你的应用程序上下文中定义了一个服务器, 其他的 LDAP namespace-defined beans将自动使用. 否则, 你可以给这个元素一个 "id"属性和从其他命名空间bean引用它使用 server-ref
属性. 这实际上是 ContextSource
的bean`id`实例, 如果你想在其它传统的Spring beans使用它.
<ldap-server> 属性
-
id bean标识符, 用于指向bean的上下文中.
-
ldif 显式指定LDIF文件资源加载到嵌入式LDAP服务器.ldif应该是一个Spring资源模式(i.e. classpath:init.ldiff). 默认为 classpath*:*.ldiff
-
manager-dn 用户名 (DN) 的 "manager" 用户标识 将用于验证(non-embedded) LDAP 服务. 如果省略, 将使用匿名访问.
-
manager-password 密码管理器DN. 如果 manager-dn被指定,这是必需的.
-
port 指定一个IP端口号码. 用于配置嵌入式LDAP服务器, 例如. 默认值为 33389.
-
root 对于嵌入式LDAP服务器可选根后缀. 默认为 "dc=springframework,dc=org"
-
url 指定LDAP服务器URL时不使用嵌入式LDAP服务器.
<ldap-authentication-provider>
这元素是速记 LdapAuthenticationProvider
实例的创建.默认情况下这将配置一个` bindauthenticator 实例和一个 `DefaultAuthoritiesPopulator
.和所有命名空间身份验证提供程序一样, 它必须包含作为 authentication-provider
元素的子元素.
<ldap-authentication-provider>父元素
<ldap-authentication-provider> 属性
-
group-role-attribute 包含角色名的LDAP属性名将用于Spring Security. 映射到
DefaultLdapAuthoritiesPopulator
的groupRoleAttribute
属性. 默认到 "cn".
-
group-search-base 组成员搜索. 映射
DefaultLdapAuthoritiesPopulator
的groupSearchBase
构造函数的参数. 默认为 "" (从根搜索).
-
group-search-filter 组搜索过滤器. 映射到
DefaultLdapAuthoritiesPopulator
的groupSearchFilter
属性. 默认为 (uniqueMember={0}). 替换参数是用户的DN.
-
role-prefix 一个非空字符串前缀将被添加到从持久性加载的角色字符串中. 映射到
DefaultLdapAuthoritiesPopulator
的rolePrefix
属性. 默认为 "ROLE_".在默认为非空的情况下,使用没有前缀的值"none".
-
server-ref 可选的服务器使用. 如果省略, 和一个默认注册的LDAP 服务 (使用没ID的 <ldap-server>), that server will be used.
-
user-context-mapper-ref 允许用户定制的加载对象明确指定userdetailscontextmapper bean将被称为来自用户目录项的上下文信息
-
user-details-class 允许用户输入的类被指定。如果设置,框架会尝试加载标准属性的定义的类的对象返回到userdetails
-
user-dn-pattern 如果你的用户在目录中的一个固定的位置(即你可以直接从用户名DN不做目录搜索), 您可以使用此属性直接映射到DN. 它直接映射到
userDnPatterns
属性AbstractLdapAuthenticator
. 值是一个特定的模式用于构建用户的DN, 例如"uid={0},ou=people". The key "{0}" 必须存在,并将被替换的用户名.
-
user-search-base 搜索用户搜索库. 默认为 "". 只使用一个 'user-search-filter'.
如果你需要执行搜索来定位目录中的用户,然后,您可以设置这些属性来控制搜索.
BindAuthenticator
将配置一个FilterBasedLdapUserSearch
和属性值直接映射到bean的构造函数的前两个参数. 如果这些属性没有设置并没有"user-dn-pattern"提供作为替代, 然后默认搜索值user-search-filter="(uid={0})"
和user-search-base=""
将被使用.
-
user-search-filter LDAP筛选器用于搜索用户(可选).例如"(uid={0})".被替换的参数是用户的登录名.
如果你需要执行搜索来定位目录中的用户,然后,你可以设置这些属性来控制搜索.
BindAuthenticator
将配置一个FilterBasedLdapUserSearch
并且属性值将直接映射到bean构造函数的前两个参数. 如果还没有设置这些属性和没有提供给user-dn-pattern
作为替代, 然后默认搜索值user-search-filter="(uid={0})"
和user-search-base=""
将被使用.
<ldap-authentication-provider>子元素
<password-compare>
作为子元素被用于 <ldap-provider>
与从` bindauthenticator 到
passwordcomparisonauthenticator `交换机的认证策略.
<password-compare>父元素
<password-compare> 属性
-
hash 定义用于用户密码的散列算法.我们强烈建议不要使用MD4,因为它是一个非常弱的散列算法.
-
password-attribute 包含用户密码的目录中的属性. 默认为 "userPassword".
<password-compare>子元素
<ldap-user-service>
这个元素配置一个LDAP UserDetailsService
. 使用的类 LdapUserDetailsService
是 FilterBasedLdapUserSearch
和 DefaultLdapAuthoritiesPopulator
的组合. 它支持的属性如在<ldap-provider>
中有相同的用法.
<ldap-user-service> 属性
-
cache-ref 定义引用一个缓存用于 UserDetailsService.
-
group-role-attribute 包含角色名的LDAP属性名将用于Spring Security. 默认为 "cn".
-
group-search-base 组成员搜索.默认为"" (从根搜索).
-
group-search-filter 组过滤搜索器. 默认为 (uniqueMember={0}). 替代参数是用户的DN.
-
id bean标识符, 用于指向bean的上下文中.
-
role-prefix 一个非空字符串前缀将被添加到从持久性加载的角色字符串中(例如. "ROLE_"). 在默认为非空的情况下,使用没有前缀的值 "none" .
-
server-ref 可选服务器使用. 如果省略, 和一个被默认注册的LDAP服务器(使用 没有ID的<ldap-server>), 该服务器将被使用.
-
user-context-mapper-ref 通过指定一个可加载的用户对象的显式定制一个UserDetailsContextMapper bean,从用户的目录条目调用上下文信息.
-
user-details-class 允许用户输入指定的对象类.如果设置,该框架将会尝试加载标准属性的定义的类的对象返回到UserDetails
-
user-search-base 搜索用户搜索库. 默认为 "". 只使用一个 'user-search-filter'.
-
user-search-filter LDAP筛选器用于搜索用户(可选).例如"(uid={0})".被替换的参数是用户的登录名.
Spring Security依赖关系
T他的附录提供了一个 Spring Security参考模块和附加的依赖关系,他们需要在运行中的应用程序的功能. 我们不包括只用来构建或测试Spring Security 本身的依赖关系. 也不包括了依赖关系所必需的外部依赖.
在项目网站上列出了所需的Spring 版本, 因此,Spring依赖之下 特定的版本被省略.注意,下面列出的一些作为“可选”依赖关系下可能仍然需要在一个Spring应用程序中的其他非安全功能.如果它们在大多数应用中使用也被列为"optional"的依赖关系,实际上可能不被标记为在项目的Maven POM文件.只有在某种意义上他们是"optional" 他们是“可选的”只有在某种意义上,你不需要他们,除非你是使用指定的功能.
其中一个模块依赖于另一个Spring Security模块,模块的非可选依赖关系取决于被假定为是必需的和没有单独列出的.
spring-security-core
使用Spring Security核心模块必须包含在任何项目中.
Dependency | 版本 | 描述 |
---|---|---|
aopalliance | 1.0 | 所需的安全实现方法. |
ehcache | 1.6.2 | 要求 ehcache-based基于用户缓存实现(可选). |
spring-aop | 基于Spring AOP的方法安全性 | |
spring-beans | Spring配置所需 | |
spring-expression | 基于表达式所需的方法安全性(可选) | |
spring-jdbc | 如果需要使用一个数据库来存储用户数据(可选). | |
spring-tx | 如果需要使用一个数据库来存储用户数据(可选). | |
aspectjrt | 1.6.10 | 如果需要使用AspectJ支持(可选). |
jsr250-api | 1.0 | 如果需要你使用JSR-250方法安全性注释(可选). |
spring-security-remoting
这个模块通常需要在Web应用程序中使用Servlet API.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-web | 使用HTTP的客户所需的远程支持. |
spring-security-web
这个模块通常需要在Web应用程序中使用Servlet API.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-web | 广泛使用Spring web支持类. | |
spring-jdbc | 需要基于JDBC的免登陆标记库(可选). | |
spring-tx | 需要通过免登陆持久标记库实现(可选). |
spring-security-ldap
这个模块是如果需要你使用LDAP认证.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-ldap-core | 1.3.0 | LDAP仅支持于Spring LDAP. |
spring-tx | 数据异常类是必需的. | |
apache-ds [13] | 1.5.5 | 如果需要你使用嵌入式LDAP服务器(可选). |
shared-ldap | 0.9.15 | 如果需要你使用嵌入式LDAP服务器(可选). |
ldapsdk | 4.1 | Mozilla LdapSDK.如果你使用OpenLDAP的密码策略功能,用于解码LDAP密码策略控制,例如. |
spring-security-config
这个模块是如果需要你使用Spring Security命名空间的配置.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-security-web | 如果需要你使用任何与Web相关的命名空间配置(可选). | |
spring-security-ldap | 如果需要你使用LDAP命名空间选项(可选). | |
spring-security-openid | 如果需要你使用OpenID认证(可选). | |
aspectjweaver | 1.6.10 | 如果需要你使用命名空间的语法点的保护(可选). |
spring-security-acl
ACL模块.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
ehcache | 1.6.2 | 如果需要实现使用基于ACL的Ehcache缓存 (optional if you are using your own implementation). |
spring-jdbc | 如果需要你使用默认的基于JDBC的aclservice (optional if you implement your own). | |
spring-tx | 如果需要你使用默认的基于JDBC的aclservice AclService (optional if you implement your own). |
spring-security-cas
CAS模块提供集成JA-SIG CAS.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-security-web | ||
cas-client-core | 3.1.12 | JA-SIG CAS客户端. 这是Spring Security集成的基础. |
ehcache | 1.6.2 | 如果需要你基于缓存Ehcache标签 (可选). |
spring-security-openid
OpenID模块.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-security-web | ||
openid4java-nodeps | 0.9.6 | Spring Security的OpenID集成使用OpenID4Java. |
httpclient | 4.1.1 | openid4java-nodeps 取决于 HttpClient 4. |
guice | 2.0 | openid4java-nodeps 取决于 Guice 2. |
spring-security-taglibs
提供Spring Security的JSP标记的实现.
Dependency | 版本 | 描述 |
---|---|---|
spring-security-core | ||
spring-security-web | ||
spring-security-acl | 如果需要你使用 | |
spring-expression | 如果需要你在标签访问限制中使用SPEL表达式 |
包括::_includes/faq.adoc[]
包括::_includes/migrating.adoc[]
filter-chain-map
,但弃用构造函数参数的注入。
参数附加到URL分号后。然而,RFC允许这些参数的URL中的任何路径段的存在
FilterChainProxy
的原始值将被退回,仍然会提供给应用程序。
HttpSessionContextIntegrationFilter
和存储方面的全部工作由过滤器本身进行执行。如果你熟悉这个类,那么其中大部分可用的配置选项现在可以在
HttpSessionSecurityContextRepository
找到。
AuthenticationProcessingFilter
和入口点被称为
AuthenticationProcessingFilterEntryPoint
。由于框架现在支持多种不同形式的身份验证,他们在3.0都被给出更具体的名称。
DigestAuthenticationFilter.passwordAlreadyEncoded
设置为
true
。然而,其他密码编码不会使用摘要式身份验证。
apacheds-core
,
apacheds-core-entry
,
apacheds-protocol-shared
,
apacheds-protocol-ldap
and
apacheds-server-jndi
are required.