# 8. 保障资金流动

## 8.1.导言

安全性对于任何应用程序都是一个重要的概念。最终用户不应该仅仅通过猜测 URL 就能够访问网站的任何部分。网站的敏感区域必须确保只处理授权的请求。 Spring 安全性是一种经过验证的安全平台，可以在多个级别上与你的应用程序集成。本节将重点讨论保护流执行的问题。

## 8.2.我如何确保一个流程？

确保流执行的安全性是一个三步过程：

* 使用身份验证和授权规则配置 Spring 安全性

* 用受保护的元素注释流定义，以定义安全规则

* 添加 SecurityFlowExecutionListener 以处理安全规则。

这些步骤中的每一个都必须完成，否则将不应用流安全规则。

## 8.3.安全元件

安全元素指定其包含的元素在完全进入之前应用授权检查。这可能不会在每个被保护的流执行阶段中发生一次。

可以保证流执行的三个阶段：流、状态和转换。在每种情况下，安全元素的语法都是相同的。固定元件位于它所固定的元件内部。例如，要保护状态，受保护元素直接发生在该状态内：

```
<view-state id="secured-view">
    <secured attributes="ROLE_USER" />
    ...
</view-state>
		
```

### 8.3.1.安全属性

`attributes`属性是 Spring 安全授权属性的逗号分隔列表。通常，这些都是特定的安全角色。 Spring 安全访问决策管理器将这些属性与用户授予的属性进行比较。

```
<secured attributes="ROLE_USER" />
			
```

默认情况下，基于角色的访问决策管理器用于确定是否允许用户访问。如果你的应用程序不使用授权角色，则需要重写此内容。

### 8.3.2.匹配类型

有两种类型的匹配可用：`any`和`all`。如果至少向用户授予了一个所需的安全属性，则允许访问。All，只有当每个所需的安全属性都被授予给用户时，才允许访问。

```
<secured attributes="ROLE_USER, ROLE_ANONYMOUS" match="any" />
			
```

这个属性是可选的。如果未定义，默认值为`any`。

只有在使用默认的访问决策管理器时，才会尊重`match`属性。

## 8.4.SecurityFlowExecutionListener

在流中定义安全规则本身并不能保护流的执行。还必须在 WebFlow 配置中定义`SecurityFlowExecutionListener`，并将其应用于流执行器。

```
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-listeners>
        <webflow:listener ref="securityFlowExecutionListener" />
    </webflow:flow-execution-listeners>
</webflow:flow-executor>

<bean id="securityFlowExecutionListener"
      class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
		
```

如果拒绝访问应用程序的一部分，将抛出`AccessDeniedException`。此异常稍后将被 Spring Security 捕获，并用于提示用户进行身份验证。重要的是，允许此异常在执行堆栈中不受约束地向上移动，否则可能不会提示最终用户进行身份验证。

### 8.4.1.自定义访问决策管理器

如果你的应用程序使用的是不基于角色的权限，则需要配置一个自定义`AccessDecisionManager`。通过在安全侦听器上设置`accessDecisionManager`属性，可以覆盖默认的决策管理器。请咨询[Spring Security reference documentation](http://static.springframework.org/spring-security/site/reference.html)以了解更多有关决策经理的信息。

```
<bean id="securityFlowExecutionListener"
      class="org.springframework.webflow.security.SecurityFlowExecutionListener">
    <property name="accessDecisionManager" ref="myCustomAccessDecisionManager" />
</bean>
			
```

## 8.5.配置 Spring 安全性

Spring 安全性具有可供选择的健壮配置。由于每个应用程序和环境都有自己的安全需求，因此[Spring Security reference documentation](http://static.springframework.org/spring-security/site/reference.html)是学习可用选项的最佳位置。

`booking-faces`和`booking-mvc`示例应用程序都被配置为使用 Spring 安全性。在 Spring 和 web.xml 级别都需要配置。

### 8.5.1. Spring 配置

Spring 配置定义了`http`细节（例如受保护的 URL 和登录/注销机制）和`authentication-provider`。对于样例应用程序，配置了本地身份验证提供程序。

```
<security:http auto-config="true">
    <security:form-login login-page="/spring/login"
                         login-processing-url="/spring/loginProcess"
                         default-target-url="/spring/main"
                         authentication-failure-url="/spring/login?login_error=1" />
    <security:logout logout-url="/spring/logout" logout-success-url="/spring/logout-success" />
</security:http>

<security:authentication-provider>
    <security:password-encoder hash="md5" />
    <security:user-service>
        <security:user name="keith" password="417c7382b16c395bc25b5da1398cf076"
                       authorities="ROLE_USER,ROLE_SUPERVISOR" />
        <security:user name="erwin" password="12430911a8af075c6f41c6976af22b09"
                       authorities="ROLE_USER,ROLE_SUPERVISOR" />
        <security:user name="jeremy" password="57c6cbff0d421449be820763f03139eb"
                       authorities="ROLE_USER" />
        <security:user name="scott" password="942f2339bf50796de535a384f0d1af3e"
                       authorities="ROLE_USER" />
    </security:user-service>
</security:authentication-provider>
			
```

### 8.5.2.web.xml 配置

在`web.xml`文件中，定义了一个`filter`来拦截所有请求。此筛选器将监听登录/注销请求，并对其进行相应的处理。它还将捕获`AccesDeniedException`s 并将用户重定向到登录页面。

```
<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>
			
```