<http>元素会创建一个FilterChainProxy 和filter 使用的bean,也可以在web.xml中自定义filter-name,不使用默认filterChainProxy的实现springSecurityFilterChain,可以自定义他
的实例MyLoginFilter,这个名字必须和过滤器类的名字一样。
<authentication-provider> 元素创建了一个DaoAuthenticationProvider bean ,<user-service>元素创建了一个InMemoryDaoImpl。所有authentication-provider
元素必须作为<authentication-manager> 的子元素, 它创建了一个ProviderManager,并把authentication provider 注册到它里面
default-target-url,always-use-default-target 属性配置成"true",这样用户就会一直跳转到这一页
<authentication-provider user-service-ref='myUserDetailsService'/>表示自定义了一个Spring Security的UserDetailsService,下面可以这样写:
<authentication-manager> <authentication-provider user-service-ref='myUserDetailsService'/> </authentication-manager>
如果你想用数据库,可以使用下面的方式
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="securityDataSource"/>
</authentication-provider>
</authentication-manager>
这里的“securityDataSource”就是DataSource bean 在application context 里的名字,它指向了包含着Spring Security 用户信息的表。
另外,你可以配置一个SpringSecurity JdbcDaoImpl bean,使用user-service-ref 属性指定:
<authentication-manager>
<authentication-provider user-service-ref='myUserDetailsService'/>
</authentication-manager>
<beans:bean id="myUserDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
你也可以使用标准的AuthenticationProvider 类,像下面
<authentication-manager>
<authentication-provider ref='myAuthenticationProvider'/>
</authentication-manager>
这里myAuthenticationProvider 是你的application context 中的一个bean 的名字,它实现了AuthenticationProvider
下面是指定访问的端口信息:
<http>
<port-mappings>
<port-mapping http="9080" https="9443"/>
</port-mappings>
</http>
检测失效的session ID,通过session-management的invalid-session-url="/sessionTimeout.htm"元素进行配置
首先,你需要把下面的监听器添加到你的web.xml 文件里,让Spring Security 获得session 生存周期事件:
<listener> <listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class> </listener>
然后,在你的application context 加入如下部分:
<http>
<session-management>
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> 防止用户第二次登陆
</session-management>
</http>
newSession - 创建一个新的“干净的”session,不会复制session 中的数据
Spring Security框架维护一个过滤器链,来提供服务,也许你会将自己的过滤器加到链条的特定位置,这些可以通过直接配置bean 获得,过滤器按照次序排列在过滤器链中
你可以把你自己的过滤器添加到队列中,使用custom-filter 元素,使用这些名字中的一个,来指定你的过滤器应该出现的位置:
<http><custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" /></http>
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>你还可以使用after 或before 属性
可以分别在position 属性使用"FIRST" 或"LAST"来指定你想让你的过滤器出现在队列元素的前面或后面,插入自定义的过滤器,而这个过滤器可能和命名空间自己创建的
标准过滤器放在同一个位置上,这样首要的是你不要错误包含命名空间的版本信息,避免使用auto-config属性,然后删除所有会创建这个过滤器的元素。
你不能替换那些<http> 元素自己使用而创建出的过滤器,比如 SecurityContextPersistenceFilter, ExceptionTranslationFilter 或 FilterSecurityInterceptor。
你可能想定义一个认证过滤器,并使用传统bean 语法定义一个入口点然后把它链接到命名空间里,就像我们已经看到的那样。对应的AuthenticationEntryPoint 可以使用<http>
元素中的entry-point-ref 属性来进行设置
默认的AccessDecisionManager,当你使用命名空间配置时,默认的AccessDecisionManager 实例会自动注册,然后用来为方法调用和web URL 访问做验证
自定义AccessDecisionManager,如果你需要使用一个更复杂的访问控制策略,把它设置给方法和web 安全是很简单的。对于方法安全,你可以设置global-security 里的
access-decision-manager-ref 属性,用对应AccessDecisionManager bean 在application context 里的id:
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean"></global-method-security>
web 安全安全的语法也是一样,但是放在http 元素里:<http access-decision-manager-ref="myAccessDecisionManagerBean"></http>
<authentication-manager>
<authentication-provider ref="casAuthenticationProvider"/>
</authentication-manager>
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
另一个常见的需求是,上下文中的另一个bean 可能需要引用AuthenticationManager。你可以为AuthenticationManager 注册一个别名,然后在application context 的其他
地方使用这个名字。
<security:authentication-manager alias="authenticationManager">
</security:authentication-manager>
<bean id="customizedFormLoginFilter" class="com.somecompany.security.web.CustomFormLoginFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
在3.0中,AnonymousAuthenticationFilter 已经成为了默认的<http>配置的一部分,所以<anonymous /> 元素无论是否设置auto-config都会被添加到配置中。
我们把安全主体和系统交互的信息都保存在SecurityContextHolder 中了,
用户查询Authentication 对象。你可以使用下面的代码
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
大多数Spring Security 的验证机制都返回一个UserDetails 的实例作为主体。为了让你自己的用户数据库起作用,我们常常把UserDetails 转换成你系统提供的类
,这样你就可以直接调用业务相关的方法了(比如getEmail(), getEmployeeNumber()等等)
UserDetailsService。这个接口里的唯一一个方法,接收String 类型的 用户名参数,返回UserDetails
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,这是获得从Spring Security 中获得用户信息的最常用方法
当成功通过验证时, UserDetails 会被用来建立Authentication 对象保存在SecurityContextHolder 里
好消息是我们提供了好几个UserDetailsService实现,其中一个使用了内存中的map(InMemoryDaoImpl) 另一个而是用了JDBC(JdbcDaoImpl)。虽然,大多数用户倾向于写自
己的,使用这些实现常常放到已有的数据访问对象(DAO)上,表示它们的雇员,客户或其他企业应用中的用户。记住这个优势,无论你用什么UserDetailsService 返回的数
据都可以通过SecurityContextHolder 获得,就像上面的代码片段讲的一样。
GrantedAuthority除了主体,另一个Authentication 提供的重要方法是getAuthorities(),这个方法提供了GrantedAuthority 对象数组,GrantedAuthority 是赋予到主体的权限
这些权限通常使用角色表示, 比如ROLE_ADMINISTRATOR 或ROLE_HR_SUPERVISOR
GrantedAuthority 对象通常使用UserDetailsService 读取的,GrantedAuthority 对象是应用程序范围下的授权
SecurityContextHolder,提供几种访问SecurityContext 的方式,SecurityContext,保存Authentication 信息,和请求对应的安全信息
HttpSessionContextIntegrationFilter,为了在不同请求使用,把SecurityContext 保存到HttpSession 里
Authentication,展示Spring Security 特定的主体。
GrantedAuthority,反应,在应用程序范围你,赋予主体的权限。
UserDetails,通过你的应用DAO,提供必要的信息,构建Authentication 对象。
UserDetailsService,创建一个UserDetails,传递一个String 类型的用户名(或者证书ID 或其他)。
ExceptionTranslationFilter 是一个Spring Security 过滤器负责检测任何一个Spring Security 抛出的异常。
SecurityContextHolder.getContext().setAuthentication(anAuthentication), 然后Authentication 对象会反应到所有并发线程,共享相同的SecurityContext 实例。你可
以自定义SecurityContextPersistenceFilter 的行为来创建完全新的一个线程避免影响其他的。还可以选择的是,你可以创建一个新实例,只在你暂时修改上下文的时候。这个
方法SecurityContextHolder.createEmptyContext()总会返回一个新的上下文实例。
DaoAuthenticationProvider
spring security 中最简单的AuthenticationProvider 实现是 DaoAuthenticationProvider , 这也是框架中最早支持的功能之一。它是UserDetailsService 的杠杆( 作为DAO ),
为了获得username, password 和GrantedAuthority 。它认证用户, 通过简单比较密码, 在UsernamePasswordAuthenticationToken 中,和UserDetailsService 中加载的信
息
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
<property name="saltSource" ref bean="saltSource"/>
<property name="passwordEncoder" ref="passwordEcoder"/>
</bean>
UserDetailsService实现 大多数认证供应器都是用了UserDetails 和UserDetailsService接口。调用UserDetailsService 中的单独的方法
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;返回的UserDetails 是一个接口
它提供了获得保证非空的认证信息,比如用户名,密码,授予的权限和用户账号是可用还是禁用。大多数认证供应器会使用UserDetailsService,
即使username 和password 没有实际用在这个认证决策中。它们可以使用返回的UserDetails 对象,获得它的GrantedAuthority 信息
这里的UserDetailsService 也很简单实现, 它应该为用户简单的获得认证信息,使用它们选择的持久化策略。这样说,Spring Security 包含了很多有用的基本实现,下面我们
会看到
一个简单的选择是使用安全命名空间中的
user-service 元素:
<user-service id="userDetailsService">
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
也支持使用外部的属性文件: <user-service id="userDetailsService" properties="users.properties"/>
JdbcDaoImpl
Spring Security 也包含了一个UserDetailsService, 它包含从一个JDBC 数据源中获得认证信息。内部使用了Spring JDBC,所以它避免了负责的功能完全的对象关系映射
(ORM)只用来保存用户细节。如果你的应用使用了一个ORM 工具, 你应该写一个自己的UserDetailsService 重用你已经创建了的映射文件。返回到JdbcDaoImpl, 一个配
置的例子如下所示:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
JdbcDaoImpl 会假设用户的权限都保存在authorities 表中,参考JdbcDaoImpl 的Javadoc 以获得更多的信息
Spring Security 维护了一个过滤器链,它没有在内部使用servlet 或任何其他基于servlet 的框架(比如spring mvc), 所以它没有与任何特定的
web 技术强行关联。它只管处理HttpServletRequest 和HttpServletResponse
DelegatingFilterProxy
FilterChainProxy
在web.xml 中,然后在applicationcontext 中处理实体, 管理我们的web 安全bean。这就是FilterChainProxy 所做的事情。它使用DelegatingFilterProxy (就像上面例子中那
样),但是对应的class 是org.springframework.security.web.FilterChainProxy。过滤器链是在applicationcontext 中声明的。这里有一个例子:
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/webServices/**" filters="
securityContextPersistenceFilterWithASCFalse,
basicAuthenticationFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
<sec:filter-chain pattern="/**" filters="
securityContextPersistenceFilterWithASCFalse,
formLoginFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
</sec:filter-chain-map>
</bean>
filter-chain-map 被用来设置安全过滤器链。它映射一个特定的URL 模式,到过滤器链中,从bean 名称来定义的filters 元素