Spring Security 参考手册

开始使用安全命名空间配置

在这一章,我们将看看怎么创建一个命名空间配置来使用框架的主要功能。让我们假设你想要快速的使用命名空间配置添加验证支持和访问控制和一些测试的登录到一个已经存在的网站应用程序。然后我们看看如何将验证换刀数据库和其他的安全仓库。在后续章节我们将介绍更多高级的命名空间配置选项。

web.xml 配置

你需要做的第一件事情是添加下面的过滤器定义到你的web.xml 文件:

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

这提供了一个钩子到Spring Security的网页基础设施。DelegatingFilterProxy 是一个委托了在应用的Context中定义为bean的过滤器实现的一个Spring框架类,在这种情况下,bean的名字是springSecurityFilterChain,这是网络安全命名空间创建的一个基础类。注意你不能应该自己使用这个bean名字。一旦你添加这个到你的web.xml,你就可以开始编辑你的应用程序上下文文件,网站安全服务被配置到http元素。

最小<http> 配置

开始开启网页安全你只需要:

<http>
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>

这表示,我们想要对我们应用程序中的所有URL进行安全性检测。需要角色"ROLEUSER'访问他们,我们使用一个包含username和password的表单登录到应用程序,我们希望有一个注销的URL,让我们可以登出应用程序。<http>元素是所有网站相关的命名空间功能的父元素。<intercept-url>元素定义了一个规则使用ant语法去匹配传入的请求的URL.(在网站应用基础设施章节,查看 请求匹配和 HttpFirewall 来了解匹配是如何执行的),你也可以换成正则表达式语法(查看附录了解更多)。这个access属性定义了这个匹配的规则需要的访问需求。默认是一个典型的用逗号分隔的角色列表,有其中一个符合则允许执行这个请求。前缀```ROLE```是一个标记,指示一个和用户的授权进行简单的比较。换句话说,一个简单的基于角色的检查会被应用。Spring Security的访问控制不仅限与简单角色(因此使用前缀来区分不同类型的安全属性)。后面我们会看到解释如何变化的注脚:[逗号分隔值的解释在访问属性取决于所使用的–1—实施。在Spring Security3.0,属性还可以填充一个–2—。(//_-这是啥。。郁闷)

你可以使用多个<intercept-url>元素来为不同的URL定于不同的访问需求,他是他们将按照顺序计算,第一个匹配的将会被使用,所以你必须将最特别的匹配放到最上面,你也可以添加一个method属性用来限制HTTP方法(GET, POST, PUT 等等.).

为了添加一些用户,你可以直接在命名空间直接定义一组测试数据。

<authentication-manager>
<authentication-provider>
    <user-service>
    <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
    <user name="bob" password="bobspassword" authorities="ROLE_USER" />
    </user-service>
</authentication-provider>
</authentication-manager>

如果你熟悉框架的预命名空间版本,你很可能已经猜到这里是怎么回事了。<http>元素负责创建FilterChainProxy和它使用的过滤器bean.像不正确过滤排序常见的问题是不再是一个问题,因为过滤器的位置都是预定义的。

<authentication-provider>元素创建一个 DaoAuthenticationProvider bean并且<user-service>元素创建了一个InMemoryDaoImpl。所有的严重供应商元素必须是<authentication-manager>元素的子元素。他创建一个ProviderManager并注册为验证供应商。你可以在命名空间目录找到更多信息。如果你想了解框架的重要的一些类了解他们如何使用特别是后面你想定制一些事情,你值得去查看一下。

上面的配置定义了2个用户,他们的密码和在这个应用程序里的角色(这将用于访问控制)。也可以使用用户服务从标准的属性文件载入用户信息。查看内存认证的部分文件格式的更多细节。使用<authentication-provider>元素意思是这些用户信息将被认证管理器使用到请求验证。你可以设置多个<authentication-provider>元素来定义不同的验证源每一个都会被依次访问到。

此时你应该可以开始你的应用程序,你将被要求登录。尝试一下或者尝试使用附带的项目教程示例。

表单和基本登录选项

你可能会想当系统提示你登录这些登录表单哪里来的,因为我们都没用提供任何的HTML和JSP文件。事实上我们并没有明确的设定一个登陆页的URL,Spring Security自动生成了一个,基于处理登录的URL标准值。以及登录后跳转的URL.然后命名空间提供了大量的支持,让你可以自定义这些选项,例如如果你想自己设计登录页面,你可以使用:

<http>
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>

另外请注意,我们添加了一个额外的intercept-url 元素,来指定登陆页的请求可以被任何匿名用户访问,(AuthenticatedVoter类可以提供更多IS_AUTHENTICATED_ANONYMOUSLY 被处理的细节)。 否则请求会被/**规则匹配这将是不可能访问到登录页面。这是一个常见的配置错误,将导致应用无限循环。Spring Security会产生一条经过到日志中如果你的登录页被保护了。它也可以设置让所有请求完全匹配特定模式而绕过安全过滤器,通过定义像这样单独http元素的规则:

<http pattern="/css/**" security="none"/>
<http pattern="/login.jsp*" security="none"/>

<http use-expressions="false">
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>

从Spring Security 3.1开始允许使用多个http元素来为不同的请求规则分别定义安全过滤器链配置。如果http元素的pattern属性未设置则匹配所有请求。创建不进行安全检查的规则是这个语法的一个简单的例子,这个规则会被映射到一个空的过滤链。我们将会在后面的 安全过滤器链章节找到更多细节。

多个<http>元素的使用是一个非常重要的功能, 例如它允许命名空间在一个应用程序中同时支持有状态和无状态的相同URL.之前的语法,使用filters="none"属性到一个 intercept-url元素与这一变化想抵触,在3.1将不再进行支持。

重要的的一点需要认识到,这些不安全的请求将完全无视任何Spring Security的web相关的配置或附加属性,例如通道的限定,所以在请求期间你将无法访问当前用户信息,或调用需要进行安全验证的方法。如果你想让安全过滤器链被应用另外也可以使用 access=IS_AUTHENTICATED_ANONYMOUSLY

如果你想使用基本验证来替换掉基于表单的登录,你可以将配置修改如下:

<http use-expressions="false">
<intercept-url pattern="/**" access="ROLE_USER" />
<http-basic />
</http>

当用户访问被保护的资源时,基本身份验证将优先弹出提示框来进行登录。在这种配置下如果你想使用基于表单的登录,他任然有效。例如,将登录嵌入另外一个网页。

设置默认的登录后地址

如果不是由试图访问受保护的资源促成的登录,默认目标URL就会起作用。这是一个当用户成功登录后会被带去的URL默认是/,你也可以通过配置always-use-default-targettrue让用户一直跳转到这个地址而无论用户是按需还是明确的选择登录。这在你的应用程序需要用户一直从主页开始时很有用。例如:

<http pattern="/login.htm*" security="none"/>
<http use-expressions="false">
<intercept-url pattern='/**' access='ROLE_USER' />
<form-login login-page='/login.htm' default-target-url='/home.htm'
        always-use-default-target='true' />
</http>

为了对跳转目标进行更多控制,你可以使用authentication-success-handler-ref来替代default-target-url . 这个bean的引用应该是 AuthenticationSuccessHandler的一个实例。你可以在核心过滤器章节和命名空间附录找到如何定制认证失败的流程的更多信息。

处理登出

logout元素,增加了一个登出导航到一个特定URL的支持,默认的登出URL是 /logout。但是你可以使用 logout-url属性指定为其他的URL .更多的属性你可以从附录找到。

使用其他的验证供应商

在实践中,你将需要比将一些名字添加到应用程序上下文文件中更具扩展性的数据源。你有可能想把用户信息存放在诸如数据库或者LDAP服务器中。LDAP命名空间的配置在香港的章节,这里我们就不细说。如果你的应用程序上下文中有一个Spring Security的 UserDetailsService 的实现叫做 "myUserDetailsService",你可以这样使用:

<authentication-manager>
    <authentication-provider user-service-ref='myUserDetailsService'/>
</authentication-manager>

其中“securityDataSource”是在应用程序上下文一个DataSource的 bean的名称,它指向了包含着Spring Security用户信息的表。或者,你可以在这个配置Spring Security的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是应用程序上下文的一个bean的名字,他实现了AuthenticationProvider接口。你可以设置多个验证供应商,这样这些供应商就会被按照定于的顺序被查询。看看章节 "验证管理器和命名空间" 了解AuthenticationManager在命名空间中怎么被配置。

添加密码编码器

密码应该一直使用一个尽可能安全的哈希算法进行编码(非标准的算法,例如SHA或者MD5).这在<password-encoder>中进行支持,使用bcrypt编码密码,原始的供应商配置应该类似这样:

<beans:bean name="bcryptEncoder"
    class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

<authentication-manager>
<authentication-provider>
    <password-encoder ref="bcryptEncoder"/>
    <user-service>
    <user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f"
            authorities="ROLE_USER, ROLE_ADMIN" />
    <user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f"
            authorities="ROLE_USER" />
    </user-service>
</authentication-provider>
</authentication-manager>

Bcrypt在大部分时候是一个好的选择。除非你有一个旧系统强迫你使用一个不同的算法。如果你正在使用一个简单的哈希算法或者更糟糕存储了明文密码,你应该考虑迁移到bcrypt这个更安全的选项。