16. 安全流

安全性是任何应用程序的重要概念。 终端用户不应仅通过猜测URL就能访问站点的任何部分。 站点中敏感的区域必须确保只处理经过授权的请求。 Spring Security 是一个经过验证的安全平台,可以在多个层面与您的应用程序集成。 本节重点介绍如何保护流执行的安全。spring-doc.cadn.net.cn

16.1. 我如何保护一个流程?

保护流程是一个三步过程:spring-doc.cadn.net.cn

  1. 配置 Spring Security 的身份验证和授权规则。spring-doc.cadn.net.cn

  2. 使用 secured 元素注解流定义,以定义安全规则。spring-doc.cadn.net.cn

  3. SecurityFlowExecutionListener 添加到处理安全规则的过程中。spring-doc.cadn.net.cn

必须完成上述每个步骤,否则流安全规则将不会应用。spring-doc.cadn.net.cn

16.2. secured元素

secured 元素表示其包含的元素应在完全进入之前应用授权检查。 在受保护的流程执行的每个阶段,这种情况可能不会发生超过一次。spring-doc.cadn.net.cn

可以保护流的三个阶段:流、状态和转换。 在每种情况下,secured 元素的语法是相同的。 secured 元素位于它所保护的元素内部。 例如,要保护某个状态,secured 元素直接出现在该状态的内部,如下所示:spring-doc.cadn.net.cn

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

16.2.1. 安全属性

attributes 的值是一个逗号分隔的 Spring Security 授权属性列表。 通常,这些是特定的安全角色。 这些属性会通过 Spring Security 的访问决策管理器与用户被授予的属性进行比较。spring-doc.cadn.net.cn

<secured attributes="ROLE_USER" />

默认情况下,使用基于权限的 AuthorizationManager 来确定是否允许用户访问。 如果您的应用程序未使用授权角色,则需要覆盖此设置。spring-doc.cadn.net.cn

16.2.2. 匹配类型

有两种匹配方式可用:anyallany 表示如果用户被授予了至少一个所需的安全属性,则允许访问。 all 表示只有当用户被授予了所有所需的安全属性时,才允许访问。spring-doc.cadn.net.cn

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

此属性是可选的。 如果未定义,默认值为 anyspring-doc.cadn.net.cn

仅当使用默认的访问决策管理器时,才尊重 match 属性。spring-doc.cadn.net.cn

16.3. SecurityFlowExecutionListener

在流中定义安全规则本身并不能保护流。 您还必须在 webflow 配置中定义一个 SecurityFlowExecutionListener 并将其应用于流执行器,如下所示:spring-doc.cadn.net.cn

<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 捕获,并用于提示用户进行身份验证。 重要的是,应允许此异常不受阻碍地向上传播执行堆栈。 否则,最终用户可能不会被提示进行身份验证。spring-doc.cadn.net.cn

16.3.1. 自定义授权管理器

如果您的应用程序使用了非基于角色的权限,则需要配置一个自定义的 AuthorizaitonManager。 您可以通过安全监听器上的 authorizationManagerInitializer 属性覆盖默认使用的 AuthorityAuthorizationManager。例如:spring-doc.cadn.net.cn

@Bean
SecurityFlowExecutionListener securityFlowExecutionListener() {
	SecurityFlowExecutionListener listener = new SecurityFlowExecutionListener();
	listener.setAuthorizationManagerInitializer(securityRule -> {
		// ...
	});
	return listener;
}

16.4. 配置 Spring Security

Spring Security 拥有强大的配置选项。 由于每个应用程序和环境都有其自身的安全需求,Spring Security 参考文档 是了解可用选项的最佳去处。spring-doc.cadn.net.cn

Both the booking-faces and booking-mvc 示例应用程序都配置为使用 Spring Security。 需要在 Spring 和 web.xml 层级进行配置。spring-doc.cadn.net.cn

16.4.1. Spring 配置

Spring 配置定义了 http 细节(例如受保护的 URL 和登录/注销机制)以及 authentication-provider。 对于示例应用程序,配置了一个本地身份验证提供程序。 以下示例为 Web 流配置了 Spring Security:spring-doc.cadn.net.cn

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

16.4.2. web.xml配置

web.xml文件中,定义了一个filter来拦截所有请求。 该过滤器监听登录和注销请求,并相应地处理它们。 它还会捕获AccesDeniedException实例并将用户重定向到登录页面。 以下示例定义了这样的过滤器:spring-doc.cadn.net.cn

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