15. Appendix

15.1 安全数据库架构

框架使用了各种数据库模式,本附录为它们提供了单个参考点。您只需要提供所需功能范围的表即可。

为 HSQLDB 数据库提供了 DDL 语句。您可以将这些用作定义正在使用的数据库的架构的准则。

15.1.1 用户架构

UserDetailsService(JdbcDaoImpl)的标准 JDBC 实现要求表为用户加载密码,帐户状态(启用或禁用)和权限列表(角色)。您将需要调整此架构以匹配您正在使用的数据库方言。

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

对于 Oracle 数据库

CREATE TABLE USERS (
    USERNAME NVARCHAR2(128) PRIMARY KEY,
    PASSWORD NVARCHAR2(128) NOT NULL,
    ENABLED CHAR(1) CHECK (ENABLED IN ('Y','N') ) NOT NULL
);

CREATE TABLE AUTHORITIES (
    USERNAME NVARCHAR2(128) NOT NULL,
    AUTHORITY NVARCHAR2(128) NOT NULL
);
ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY);
ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE;

Group Authorities

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实现时才需要这些表。如果您自己编写或选择不使用UserDetailsService来实现AuthenticationProvider,那么只要满足接口协定,就可以完全自由地存储数据。

15.1.2 永久登录(记住我)架构

该表用于存储更安全的persistent tokenmeme-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
);

15.1.3 ACL 架构

Spring Security ACL实现使用了四个表。

  • acl_sid存储 ACL 系统识别的安全身份。这些可以是唯一的委托人或可以应用于多个委托人的权限。

  • acl_class定义适用于 ACL 的域对象类型。 class列存储对象的 Java 类名称。

  • acl_object_identity存储特定域对象的对象标识定义。

  • acl_entry存储适用于特定对象标识和安全标识的 ACL 权限。

假设数据库将为每个身份自动生成主键。当JdbcMutableAclServiceacl_sidacl_class表中创建新行时,它们必须能够检索它们。它具有两个属性,这些属性定义检索这些值classIdentityQuerysidIdentityQuery所需的 SQL。两者都默认为call identity()

ACL 工件 JAR 包含用于在 HyperSQL(HSQLDB),PostgreSQL,MySQL/MariaDB,Microsoft SQL Server 和 Oracle 数据库中创建 ACL 模式的文件。在以下各节中还将演示这些架构。

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 varchar_ignorecase(36) 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 varchar(36) 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)
);

您必须将JdbcMutableAclServiceclassIdentityQuerysidIdentityQuery属性分别设置为以下值:

  • select currval(pg_get_serial_sequence('acl_class', 'id'))

  • select currval(pg_get_serial_sequence('acl_sid', 'id'))

MySQL 和 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 VARCHAR(36) 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 VARCHAR(36) 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(18) PRIMARY KEY,
    PRINCIPAL NUMBER(1) NOT NULL CHECK (PRINCIPAL IN (0, 1 )),
    SID NVARCHAR2(128) NOT NULL,
    CONSTRAINT ACL_SID_UNIQUE UNIQUE (SID, PRINCIPAL)
);
CREATE SEQUENCE ACL_SID_SQ START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER ACL_SID_SQ_TR BEFORE INSERT ON ACL_SID FOR EACH ROW
BEGIN
    SELECT ACL_SID_SQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END;

CREATE TABLE ACL_CLASS (
    ID NUMBER(18) PRIMARY KEY,
    CLASS NVARCHAR2(128) NOT NULL,
    CONSTRAINT ACL_CLASS_UNIQUE UNIQUE (CLASS)
);
CREATE SEQUENCE ACL_CLASS_SQ START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER ACL_CLASS_ID_TR BEFORE INSERT ON ACL_CLASS FOR EACH ROW
BEGIN
    SELECT ACL_CLASS_SQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END;

CREATE TABLE ACL_OBJECT_IDENTITY(
    ID NUMBER(18) PRIMARY KEY,
    OBJECT_ID_CLASS NUMBER(18) NOT NULL,
    OBJECT_ID_IDENTITY NVARCHAR2(64) NOT NULL,
    PARENT_OBJECT NUMBER(18),
    OWNER_SID NUMBER(18),
    ENTRIES_INHERITING NUMBER(1) NOT NULL CHECK (ENTRIES_INHERITING IN (0, 1)),
    CONSTRAINT ACL_OBJECT_IDENTITY_UNIQUE UNIQUE (OBJECT_ID_CLASS, OBJECT_ID_IDENTITY),
    CONSTRAINT ACL_OBJECT_IDENTITY_PARENT_FK FOREIGN KEY (PARENT_OBJECT) REFERENCES ACL_OBJECT_IDENTITY(ID),
    CONSTRAINT ACL_OBJECT_IDENTITY_CLASS_FK FOREIGN KEY (OBJECT_ID_CLASS) REFERENCES ACL_CLASS(ID),
    CONSTRAINT ACL_OBJECT_IDENTITY_OWNER_FK FOREIGN KEY (OWNER_SID) REFERENCES ACL_SID(ID)
);
CREATE SEQUENCE ACL_OBJECT_IDENTITY_SQ START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER ACL_OBJECT_IDENTITY_ID_TR BEFORE INSERT ON ACL_OBJECT_IDENTITY FOR EACH ROW
BEGIN
    SELECT ACL_OBJECT_IDENTITY_SQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END;

CREATE TABLE ACL_ENTRY (
    ID NUMBER(18) NOT NULL PRIMARY KEY,
    ACL_OBJECT_IDENTITY NUMBER(18) NOT NULL,
    ACE_ORDER INTEGER NOT NULL,
    SID NUMBER(18) 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 ACL_ENTRY_UNIQUE UNIQUE (ACL_OBJECT_IDENTITY, ACE_ORDER),
    CONSTRAINT ACL_ENTRY_OBJECT_FK FOREIGN KEY (ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY (ID),
    CONSTRAINT ACL_ENTRY_ACL_FK FOREIGN KEY (SID) REFERENCES ACL_SID(ID)
);
CREATE SEQUENCE ACL_ENTRY_SQ 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_SQ.NEXTVAL INTO :NEW.ID FROM DUAL;
END;

15.2 安全命名空间

本附录提供了对安全名称空间中可用元素的引用以及有关它们创建的基础 Bean 的信息(假定了解各个类以及它们如何协同工作-您可以在项目 Javadoc 和本文档的其他地方找到更多信息.)。如果您以前没有使用过命名空间,请阅读有关命名空间配置的introductory chapter,因为这是对此处信息的补充。建议在编辑基于模式的配置时使用高质量的 XML 编辑器,因为这将提供有关哪些元素和属性可用的上下文信息,以及解释其用途的 Comments。名称空间以RELAX NG Compact 格式编写,然后转换为 XSD 模式。如果您熟悉此格式,则不妨直接检查schema file

15.2.1 Web 应用程序安全性

<debug>

启用 Spring Security 调试基础结构。这将提供人类可读的(多行)调试信息,以监视进入安全过滤器的请求。这可能包括敏感信息,例如请求参数或 Headers,并且仅应在开发环境中使用。

<http>

如果在应用程序中使用<http>元素,则会创建一个名为“ springSecurityFilterChain”的FilterChainProxy bean,并且该元素中的配置用于在FilterChainProxy中构建过滤器链。从 Spring Security 3.1 开始,其他http元素可用于添加额外的过滤器链[22]。某些核心过滤器始终在过滤器链中创建,而其他核心过滤器将根据存在的属性和子元素添加到堆栈中。标准过滤器的位置是固定的(请参见名称空间介绍中的过滤器 Order 表),当用户必须在FilterChainProxy bean 中显式配置过滤器链时,消除了以前版本框架中常见的错误源。当然,如果需要完全控制配置,您仍然可以这样做。

所有需要引用AuthenticationManager的过滤器都将自动注入由名称空间配置创建的内部实例(有关AuthenticationManager的更多信息,请参见introductory chapter)。

每个<http>名称空间块始终创建SecurityContextPersistenceFilterExceptionTranslationFilterFilterSecurityInterceptor。这些是固定的,不能用替代方法替代。

<http> Attributes

<http>元素上的属性控制核心过滤器上的某些属性。

  • access-decision-manager-ref 可选属性,指定用于授权 HTTP 请求的AccessDecisionManager实现的 ID。默认情况下,AffirmativeBased实现用于RoleVoterAuthenticatedVoter

  • authentication-manager-ref 对此 http 元素创建的FilterChain使用的AuthenticationManager的引用。

  • auto-config 自动注册登录表单,BASIC 身份验证,注销服务。如果设置为“ true”,则会添加所有这些功能(尽管您仍然可以通过提供相应的元素来自定义每个功能的配置)。如果未指定,则默认为“ false”。不建议使用此属性。请使用显式配置元素来避免混淆。

  • create-session 控制 Spring Security 类创建 HTTP 会话的迫切性。选项包括:

  • always-如果不存在会话,Spring Security 将主动创建一个会话。

    • ifRequired-仅在需要会话时,Spring Security 才会创建一个会话(默认值)。

    • never-Spring Security 永远不会创建会话,但是如果应用程序创建会话,它将使用一个会话。

    • stateless-Spring Security 将不会创建会话,并且会忽略用于获取 Spring Authentication的会话。

  • disable-url-rewriting 禁止将会话 ID 附加到应用程序中的 URL。如果此属性设置为true,则 Client 端必须使用 cookie。默认值为true

  • entry-point-ref 通常,所使用的AuthenticationEntryPoint将根据已配置的身份验证机制进行设置。此属性允许通过定义自定义的AuthenticationEntryPoint bean(将启动身份验证过程)来覆盖此行为。

  • jaas-api-provision (如果可用),以从JaasAuthenticationToken获取的Subject运行请求,该请求是通过向堆栈中添加JaasApiIntegrationFilter bean 来实现的。默认为false

  • 名称 Bean 标识符,用于引用上下文中其他位置的 Bean。

  • 每次请求一次 对应于FilterSecurityInterceptorobserveOncePerRequest属性。默认为true

  • 模式http元素定义模式可控制将通过其定义的过滤器列表进行过滤的请求。解释取决于配置的request-matcher。如果未定义任何模式,则将匹配所有请求,因此应首先声明最具体的模式。

  • realm 设置用于基本身份验证的领域名称(如果启用)。对应于BasicAuthenticationEntryPointrealmName属性。

  • request-matcher 定义FilterChainProxy中使用的RequestMatcher策略以及intercept-url创建的 Bean 以匹配传入的请求。当前的选项分别是mvcantregexciRegex,分别用于 Spring MVC,ant,regular-expression 和不区分大小写的正则表达式。使用其patternmethodservlet-path属性为每个intercept-url元素创建一个单独的实例。使用AntPathRequestMatcher匹配 Ant 路径,使用RegexRequestMatcher匹配正则表达式,对于 Spring MVC 路径使用MvcRequestMatcher匹配。有关这些类的确切执行方式的更多详细信息,请参见 Javadoc。Ant 路径是默认策略。

  • request-matcher-ref 对实现RequestMatcher的 bean 的引用,它将确定是否应使用此FilterChain。这是pattern的更强大的替代方法。

  • 安全 通过将此属性设置为none,可以将请求模式 Map 到一个空的过滤器链。不会应用任何安全性,并且 Spring Security 的任何功能都不可用。

  • security-context-repository-ref 允许将自定义SecurityContextRepository注入SecurityContextPersistenceFilter

  • servlet-api-provision 提供HttpServletRequest安全方法的版本,例如isUserInRole()getPrincipal(),这些方法是通过将SecurityContextHolderAwareRequestFilter bean 添加到堆栈中来实现的。默认为true

<http>的子元素

<access-denied-handler>

该元素允许您使用error-page属性为ExceptionTranslationFilter使用的默认AccessDeniedHandler设置errorPage属性,或者使用ref属性提供自己的实现。关于ExceptionTranslationFilter的部分将对此进行详细讨论。

<access-denied-handler>的父元素
<access-denied-handler> Attributes

  • 错误页面 如果请求验证的用户请求其无权访问的页面,则重定向到该页面的访问被拒绝页面。

  • ref 定义对AccessDeniedHandler类型的 Spring bean 的引用。

<cors>

该元素允许配置CorsFilter。如果未指定CorsFilterCorsConfigurationSource并且 Spring MVC 在 Classpath 中,则将HandlerMappingIntrospector用作CorsConfigurationSource

<cors> Attributes

<cors>元素上的属性控制 headers 元素。

  • ref 可选属性,用于指定CorsFilter的 bean 名称。

  • cors-configuration-source-ref 可选属性,指定要注入 XML 名称空间创建的CorsFilterCorsConfigurationSource的 bean 名称。
<cors>的父元素

<headers>

此元素允许配置要与响应一起发送的其他(安全)Headers。它可以轻松配置多个 Headers,还可以通过header元素设置自定义 Headers。其他信息,可以在参考的Security Headers部分中找到。

  • Cache-ControlPragmaExpires-可以使用cache-control元素进行设置。这样可以确保浏览器不会缓存您的安全页面。

  • Strict-Transport-Security-可以使用hsts元素进行设置。这样可以确保浏览器自动请求 HTTPS 进行后续请求。

  • X-Frame-Options-可以使用frame-options元素进行设置。 X-Frame-OptionsHeaders 可用于防止点击劫持攻击。

  • X-XSS-Protection-可以使用xss-protection元素进行设置。浏览器可以使用X-XSS-ProtectionHeaders 进行基本控制。

  • X-Content-Type-Options-可以使用content-type-options元素进行设置。 X-Content-Type-OptionsHeaders 可防止 Internet Explorer 从 MIME 嗅探已声明的 Content Type 的响应。下载扩展程序时,这也适用于 Google Chrome。

  • Public-Key-PinningPublic-Key-Pinning-Report-Only-可以使用hpkp元素进行设置。这允许 HTTPS 网站使用错误签发或欺诈性证书来抵制攻击者的冒名顶替。

  • Content-Security-PolicyContent-Security-Policy-Report-Only-可以使用content-security-policy元素进行设置。 内容安全 Policy(CSP)是一种机制,Web 应用程序可以利用该机制来减轻内容注入漏洞,例如跨站点脚本(XSS)。

  • Referrer-Policy-可以使用referrer-policy元素进行设置,Referrer-Policy是 Web 应用程序可以用来 Management 引荐来源网址字段的机制,该字段包含用户所在的最后一页。

  • Feature-Policy-可以使用feature-policy元素进行设置,Feature-Policy是一种机制,可让 Web 开发人员有选择地启用,禁用和修改浏览器中某些 API 和 Web 功能的行为。

<headers> Attributes

<headers>元素上的属性控制 headers 元素。

  • defaults-disabled 可选属性,用于指定禁用默认的 Spring Security 的 HTTP 响应头。默认值为 false(包括默认标题)。

  • disabled 可选属性,用于指定禁用 Spring Security 的 HTTP 响应 Headers。缺省值为 false(已启用 Headers)。
<headers>的父元素
<headers>的子元素

<cache-control>

添加Cache-ControlPragmaExpiresHeaders,以确保浏览器不缓存您的安全页面。

<cache-control> Attributes

  • disabled 指定是否应禁用缓存控制。默认为 false。
<cache-control>的父元素

<hsts>

启用后,会将Strict-Transport-SecurityHeaders 添加到任何安全请求的响应中。这允许服务器指示浏览器自动将 HTTPS 用于将来的请求。

<hsts> Attributes

  • disabled 指定是否应禁用 Strict-Transport-Security。默认为 false。

  • include-sub-domains 指定是否应包含子域。默认为 true。

  • max-age-seconds 指定将主机视为已知 HSTS 主机的最长时间。默认一年。

  • request-matcher-ref 用来确定是否应设置 Headers 的 RequestMatcher 实例。默认值为 HttpServletRequest.isSecure()为 true。
<hsts>的父元素

<hpkp>

启用后,会将HTTP 的公钥固定扩展Headers 添加到任何安全请求的响应中。这允许 HTTPS 网站使用错误签发或欺诈性证书来抵制攻击者的冒名顶替。

<hpkp> Attributes

  • disabled 指定是否应禁用 HTTP 公钥固定(HPKP)。默认为 true。

  • include-sub-domains 指定是否应包含子域。默认为 false。

  • max-age-seconds 设置 Public-Key-PinsHeaders 的 max-age 指令值。默认为 60 天。

  • 仅报告 指定浏览器是否仅应报告引脚验证失败。默认为 true。

  • report-uri 指定浏览器应向其报告引脚验证失败的 URI。
<hpkp>的父元素

<pins>

引脚列表

<pins>的子元素

<pin>

使用 base64 编码的 SPKI 指纹作为值并使用密码哈希算法作为属性来指定引脚

<pin> Attributes

  • 算法 密码哈希算法。默认值为 SHA256.
<pin>的父元素

<content-security-policy>

启用后,将内容安全 Policy(CSP)Headers 添加到响应中。 CSP 是 Web 应用程序可以用来减轻内容注入漏洞(例如跨站点脚本(XSS))的机制。

<content-security-policy> Attributes

  • policy-directives Content-Security-PolicyHeaders 的安全策略指令,或者如果将 report-only 设置为 true,则使用 Content-Security-Policy-Report-OnlyHeaders。

  • 仅报告 设置为 true,以启用 Content-Security-Policy-Report-OnlyHeaders 仅用于报告策略违规。默认为 false。
<content-security-policy>的父元素

<referrer-policy>

启用后,将Referrer PolicyHeaders 添加到响应中。

<referrer-policy> Attributes

  • policy Referrer-PolicyHeaders 的策略。默认为“无引荐来源”。
<referrer-policy>的父元素

<feature-policy>

启用后,将Feature PolicyHeaders 添加到响应中。

<feature-policy> Attributes

  • policy-directives Feature-PolicyHeaders 的安全策略指令。
<feature-policy>的父元素

<frame-options>

启用后,会将X-Frame-Options header添加到响应中,这使较新的浏览器可以进行一些安全检查并防止clickjacking攻击。

<frame-options> Attributes

  • disabled 如果禁用,则不包含 X-Frame-OptionsHeaders。默认为 false。

  • policy

  • DENY该页面无法显示在框架中,无论网站试图这样做。当指定 frame-options-policy 时,这是默认设置。

    • SAMEORIGIN该页面只能以与页面本身相同的原点显示在一个框架中

    • ALLOW-FROM origin该页面只能显示在指定原点的框架中。

换句话说,如果指定 DENY,则从其他站点加载时,不仅尝试在框架中加载页面失败,而且从同一站点加载时,尝试也会失败。另一方面,如果指定 SAMEORIGIN,则只要框架中包含该站点的页面与提供该页面的站点相同,您仍可以在框架中使用该页面。

  • 策略 选择使用 ALLOW-FROM 策略时要使用的AllowFromStrategy

  • static使用单个静态 ALLOW-FROM 值。可以通过value属性设置该值。

    • regexp使用 regelur 表达式来验证传入请求以及是否允许传入请求。可以通过value属性设置正则表达式。可以使用from-parameter指定用于检索要验证的值的请求参数。

    • whitelist包含允许的域的逗号分隔列表。可以通过value属性设置逗号分隔的列表。可以使用from-parameter指定用于检索要验证的值的请求参数。

  • ref 除了使用 sched 义策略之一之外,还可以使用自定义AllowFromStrategy。可以通过此 ref 属性指定对该 bean 的引用。

  • 使用 ALLOW-FROM strategy时要使用的值。

  • from-parameter 指定将 regexp 或白名单用于 ALLOW-FROM 策略时要使用的请求参数的名称。
<frame-options>的父元素

<xss-protection>

X-XSS-Protection header添加到响应中,以帮助防范反映的/ Type-1 跨站点脚本(XSS)攻击。这绝不是对 XSS 攻击的全面保护!

<xss-protection> Attributes

  • xss-protection-block 如果为 true 并且 xss-protection-enabled 为 true,则将 mode = block 添加到 Headers 中。这向浏览器指示根本不应加载该页面。如果为 false 并且 xss-protection-enabled 为 true,则在检测到反射攻击时仍将呈现页面,但将修改响应以防止受到攻击。请注意,有时存在绕过此模式的方法,这些方法通常常常使阻塞页面更为可取。
<xss-protection>的父元素

<content-type-options>

将带有 nosniff 值的 X-Content-Type-OptionsHeaders 添加到响应中。此disables MIME-sniffing用于 IE8 和 Chrome 扩展程序。

<content-type-options> Attributes

  • disabled 指定是否应禁用“Content Type 选项”。默认为 false。
<content-type-options>的父元素

将其他 Headers 添加到响应中,需要同时指定名称和值。

<header-attributes> Attributes

  • header-name 标题的name

  • 要添加的标题的value

  • ref 指的是HeaderWriter接口的自定义实现。
<header>的父元素

<anonymous>

AnonymousAuthenticationFilter添加到堆栈中,并将AnonymousAuthenticationProvider添加到堆栈中。如果使用IS_AUTHENTICATED_ANONYMOUSLY属性,则为必需。

<anonymous>的父元素
<anonymous> Attributes

  • 启用 使用默认名称空间设置,将自动启用匿名“身份验证”功能。您可以使用此属性禁用它。

  • granted-authority 应该分配给匿名请求的授权权限。通常,这用于为匿名请求分配特定角色,随后可以在授权决策中使用这些角色。如果未设置,则默认为ROLE_ANONYMOUS

  • 密钥 提供者和过滤器之间共享的密钥。通常不需要设置。如果未设置,则默认为安全随机生成的值。这意味着在使用匿名功能时设置此值可以缩短启动时间,因为安全的随机值可能需要一段时间才能生成。

  • username 应该分配给匿名请求的用户名。这样可以确定主体,这对于日志记录和审核可能很重要。如果未设置,则默认为anonymousUser

<csrf>

此元素将为应用程序添加跨站请求伪造(CSRF)保护。它还将默认的 RequestCache 更新为仅在成功身份验证后重播“ GET”请求。其他信息可以在参考的跨站请求伪造(CSRF)部分中找到。

<csrf>的父元素
<csrf> Attributes

  • disabled 可选属性,用于指定禁用 Spring Security 的 CSRF 保护。默认值为 false(启用 CSRF 保护)。强烈建议使 CSRF 保护处于启用状态。

  • token-repository-ref 要使用的 CsrfTokenRepository。默认值为HttpSessionCsrfTokenRepository

  • request-matcher-ref 用来确定是否应应用 CSRF 的 RequestMatcher 实例。默认为除“ GET”,“ TRACE”,“ HEAD”,“ OPTIONS”之外的任何 HTTP 方法。

<custom-filter>

该元素用于向过滤器链添加过滤器。它不会创建任何其他 bean,而是用于选择类型javax.servlet.Filter的 bean,该 bean 已在应用程序上下文中定义,并将其添加到 Spring Security 维护的过滤器链中的特定位置。完整的详细信息可以在namespace chapter中找到。

<custom-filter>的父元素
<custom-filter> Attributes

  • 之后 紧随其后的过滤器,自定义过滤器应放置在链中。只有希望将自己的过滤器混入安全过滤器链并了解标准 Spring Security 过滤器的高级用户才需要使用此功能。过滤器名称 Map 到特定的 Spring Security 实现过滤器。

  • 之前 紧接自定义过滤器放置在链中之前的过滤器

  • position 定制过滤器在链中应放置的明确位置。如果要更换标准过滤器,请使用。

  • ref 定义对实现Filter的 Spring bean 的引用。

<expression-handler>

定义启用基于表达式的访问控制时将使用的SecurityExpressionHandler实例。如果未提供,则将使用默认实现(不支持 ACL)。

<expression-handler>的父元素
<expression-handler> Attributes

  • ref 定义对实现SecurityExpressionHandler的 Spring bean 的引用。

<form-login>

用于将UsernamePasswordAuthenticationFilter添加到过滤器堆栈,并将LoginUrlAuthenticationEntryPoint添加到应用程序上下文以按需提供身份验证。这将始终优先于其他由名称空间创建的入口点。如果未提供任何属性,则将在 URL“/login” [23]上自动生成一个登录页面。可以使用<form-login> Attributes来定制行为。

<form-login>的父元素
<form-login> Attributes

  • always-use-default-target 如果设置为true,则无论用户如何到达登录页面,用户将始终从default-target-url给定的值开始。Map 到UsernamePasswordAuthenticationFilteralwaysUseDefaultTargetUrl属性。默认值为false

  • authentication-details-source-ref 认证过滤器将使用的对AuthenticationDetailsSource的引用

  • authentication-failure-handler-ref 可用作authentication-failure-url的替代方法,使您在身份验证失败后可以完全控制导航流程。该值应为应用程序上下文中的AuthenticationFailureHandler bean 的名称。

  • authentication-failure-url Map 到UsernamePasswordAuthenticationFilterauthenticationFailureUrl属性。定义登录失败时浏览器将重定向到的 URL。默认为/login?error,它将由自动登录页面生成器自动处理,并使用错误消息重新呈现登录页面。

  • authentication-success-handler-ref 可以用作default-target-urlalways-use-default-target的替代方法,使您在成功通过身份验证后完全控制导航流程。该值应为应用程序上下文中AuthenticationSuccessHandler bean 的名称。默认情况下,使用SavedRequestAwareAuthenticationSuccessHandler的实现并将其注入default-target-url

  • default-target-url Map 到UsernamePasswordAuthenticationFilterdefaultTargetUrl属性。如果未设置,则默认值为“ /”(应用程序根目录)。如果将用户带到最初请求的 URL,则在尝试访问受保护的资源时不要求用户登录后,将在登录后将其带到该 URL。

  • login-page 应当用于呈现登录页面的 URL。Map 到LoginUrlAuthenticationEntryPointloginFormUrl属性。默认为“ /登录”。

  • login-processing-url Map 到UsernamePasswordAuthenticationFilterfilterProcessesUrl属性。默认值为“/login”。

  • password-parameter 包含密码的请求参数的名称。默认为“密码”。

  • username-parameter 包含用户名的请求参数的名称。默认为“用户名”。

  • authentication-success-forward-urlUsernamePasswordAuthenticationFilterForwardAuthenticationSuccessHandlerMap 到authenticationSuccessHandler属性。

  • authentication-failure-forward-urlUsernamePasswordAuthenticationFilterForwardAuthenticationFailureHandlerMap 到authenticationFailureHandler属性。

<http-basic>

BasicAuthenticationFilterBasicAuthenticationEntryPoint添加到配置中。如果未启用基于表单的登录,则后者将仅用作配置入口点。

<http-basic>的父元素
<http-basic> Attributes

  • authentication-details-source-ref 认证过滤器将使用的对AuthenticationDetailsSource的引用

  • entry-point-ref 设置BasicAuthenticationFilter使用的AuthenticationEntryPoint

<http-firewall> Element

这是一个顶级元素,可用于将HttpFirewall的自定义实现注入由名称空间创建的FilterChainProxy。默认实现应适用于大多数应用程序。

<http-firewall> Attributes

  • ref 定义对实现HttpFirewall的 Spring bean 的引用。

<intercept-url>

此元素用于定义应用程序感兴趣的 URL 模式集,并配置应如何处理它们。它用于构造FilterSecurityInterceptor使用的FilterInvocationSecurityMetadataSource。例如,如果需要通过 HTTPS 访问特定的 URL,它还负责配置ChannelProcessingFilter。当将指定的模式与传入的请求进行匹配时,将按照声明元素的 Sequences 进行匹配。因此,最具体的模式应该放在首位,最一般的模式应该放在最后。

<intercept-url>的父元素
<intercept-url> Attributes

  • access 列出将为定义的 URL 模式/方法组合存储在FilterInvocationSecurityMetadataSource中的访问属性。这应该是安全配置属性(例如角色名称)的逗号分隔列表。

  • 过滤器 只能采用值“无”。这将导致任何匹配请求完全绕过 Spring Security 过滤器链。 <http>配置的其余部分都不会对请求产生任何影响,并且在其持续时间内将没有安全上下文可用。在请求期间无法访问安全方法。

Note

  • 方法 HTTP 方法将与模式和 servlet 路径(可选)结合使用,以匹配传入的请求。如果省略,则任何方法都将匹配。如果使用和不使用方法指定了相同的模式,则特定于方法的匹配将优先。

  • pattern 定义 URL 路径的模式。内容将取决于包含 http 元素的request-matcher属性,因此默认为 ant path 语法。

  • request-matcher-refRequestMatcher的引用,该引用将用于确定是否使用此<intercept-url>

  • requires-channel 可以是“ http”或“ https”,具体取决于应分别通过 HTTP 还是 HTTPS 访问特定的 URL 模式。可替代地,当没有偏好时,可以使用值“ any”。如果此属性存在于任何<intercept-url>元素上,则ChannelProcessingFilter将添加到过滤器堆栈中,并将其附加依赖项添加到应用程序上下文中。

如果添加了<port-mappings>配置,则SecureChannelProcessorInsecureChannelProcessor bean 将使用它来确定用于重定向到 HTTP/HTTPS 的端口。

Note

  • servlet-path servlet 路径,它将与模式和 HTTP 方法结合使用以匹配传入的请求。仅当request-matcher为'mvc'时,此属性才适用。此外,仅在以下两种使用情况下才需要该值:1)在ServletContext中注册了 2 个或更多HttpServlet,它们具有以'/'开头的 Map 并且不同。 2)模式从已注册的HttpServlet路径的相同值开始,但不包括默认(根)HttpServlet '/'

Note

<jee>

将 J2eePreAuthenticatedProcessingFilter 添加到过滤器链以提供与容器身份验证的集成。

<jee>的父元素
<jee> Attributes

  • mappable-roles 逗号分隔的角色列表,用于在传入的 HttpServletRequest 中查找。

  • user-service-ref 对用户服务(或 UserDetailsService bean)ID 的引用

<logout>

LogoutFilter添加到过滤器堆栈。这是使用SecurityContextLogoutHandler配置的。

<logout>的父元素
<logout> Attributes

  • 删除 cookie 逗号分隔的 cookie 名称列表,当用户注销时应删除。

  • invalidate-session Map 到SecurityContextLogoutHandlerinvalidateHttpSession。默认为“ true”,因此会话将在注销时失效。

  • logout-success-url 注销后将被带到的目标 URL。默认为\ /注销(即/ login?logout)

设置此属性将为SessionManagementFilter注入配置了属性值的SimpleRedirectInvalidSessionStrategy。提交无效的会话 ID 后,将调用该策略,并重定向到配置的 URL。

  • logout-url 将会导致注销的 URL(即将由过滤器处理)。默认为“ /注销”。

  • success-handler-ref 可用于提供LogoutSuccessHandler的实例,该实例在注销后将被调用以控制导航。

<openid-login>

<form-login>类似,并且具有相同的属性。 login-processing-url的默认值为“/login/openid”。 OpenIDAuthenticationFilterOpenIDAuthenticationProvider将被注册。后者需要引用UserDetailsService。同样,这可以由id使用user-service-ref属性指定,或者将自动位于应用程序上下文中。

<openid-login>的父元素
<openid-login> Attributes

  • 始终使用默认目标 登录后是否应始终将用户重定向到默认目标 URL。

  • authentication-details-source-ref 对身份验证筛选器将使用的 AuthenticationDetailsSource 的引用

  • authentication-failure-handler-ref 对 AuthenticationFailureHandler bean 的引用,应用于处理失败的身份验证请求。不应与 authentication-failure-url 结合使用,因为实现应始终处理到后续目标的导航

  • authentication-failure-url 登录失败页面的 URL。如果未指定登录失败 URL,Spring Security 将在/ login?login_error 处自动创建一个失败登录 URL,并创建一个相应的过滤器以在请求时呈现该登录失败 URL。

  • authentication-success-forward-urlUsernamePasswordAuthenticationFilterForwardAuthenticationSuccessHandlerMap 到authenticationSuccessHandler属性。

  • authentication-failure-forward-urlUsernamePasswordAuthenticationFilterForwardAuthenticationFailureHandlerMap 到authenticationFailureHandler属性。

  • authentication-success-handler-ref 对 AuthenticationSuccessHandler bean 的引用,应用于处理成功的身份验证请求。不应与default-target-url(或always-use-default-target)结合使用,因为实现应始终处理导航到后续目标的操作

  • default-target-url 如果无法恢复用户的先前操作,则在成功认证后将重定向到的 URL。如果用户在未先请求触发身份验证的安全操作的情况下访问登录页面,通常会发生这种情况。如果未指定,则默认为应用程序的根目录。

  • login-page 登录页面的 URL。如果未指定登录 URL,Spring Security 将在/ login 自动创建一个登录 URL,并在请求时自动创建一个相应的过滤器来呈现该登录 URL。

  • login-processing-url 登录表单发布到的 URL。如果未指定,则默认为/ login。

  • password-parameter 包含密码的请求参数的名称。默认为“密码”。

  • user-service-ref 对用户服务(或 UserDetailsService bean)ID 的引用

  • username-parameter 包含用户名的请求参数的名称。默认为“用户名”。
<openid-login>的子元素

<attribute-exchange>

attribute-exchange元素定义应从身份提供者请求的属性列表。可以在名称空间配置一章的OpenID Support部分中找到一个示例。可以使用多个,在这种情况下,每个属性都必须具有identifier-match属性,该属性包含与提供的 OpenID 标识符匹配的正则表达式。这允许从不同的提供程序(Google,Yahoo 等)获取不同的属性列表。

<attribute-exchange>的父元素
<attribute-exchange> Attributes

  • identifier-match 一个正则表达式,当决定在身份验证期间使用哪个属性交换配置时,它将与所声明的身份进行比较。
<attribute-exchange>的子元素

<openid-attribute>

制作 OpenID AX Fetch Request时使用的属性

<openid-attribute>的父元素
<openid-attribute> Attributes

  • count 指定您希望获取的属性数量。例如,返回 3 封电子邮件。预设值为 1.

  • name 指定您希望取回的属性的名称。例如,电子邮件。

  • 必需 指定 OP 是否需要此属性,如果 OP 不返回该属性,则不会出错。默认为 false。

<port-mappings>

默认情况下,实例PortMapperImpl将添加到配置中,用于重定向到安全和不安全的 URL。可以选择使用此元素来覆盖该类定义的默认 Map。每个子<port-mapping>元素定义一对 HTTP:HTTPS 端口。默认 Map 为 80:443 和 8080:8443. namespace introduction中提供了覆盖这些示例的示例。

<port-mappings>的父元素
<port-mappings>的子元素

<port-mapping>

提供一种在强制重定向时将 http 端口 Map 到 https 端口的方法。

<port-mapping>的父元素
<port-mapping> Attributes

  • http 要使用的 http 端口。

  • https 要使用的 https 端口。

<remember-me>

RememberMeAuthenticationFilter添加到堆栈中。依次使用TokenBasedRememberMeServicesPersistentTokenBasedRememberMeServices或由用户指定的 Bean 来实现RememberMeServices,具体取决于属性设置。

<remember-me>的父元素
<remember-me> Attributes

  • authentication-success-handler-ref 如果需要自定义导航,请在RememberMeAuthenticationFilter上设置authenticationSuccessHandler属性。该值应为应用程序上下文中AuthenticationSuccessHandler bean 的名称。

  • data-source-refDataSource bean 的引用。如果已设置,则将使用PersistentTokenBasedRememberMeServices并将其配置为JdbcTokenRepositoryImpl实例。

  • remember-me-parameter 切换“记住我”身份验证的请求参数的名称。默认为“记住我”。Map 到AbstractRememberMeServices的“参数”属性。

  • remember-me-cookie cookie 名称,用于存储用于“记住我”身份验证的令牌。默认为“记住我”。Map 到AbstractRememberMeServices的“ cookieName”属性。

  • key Map 到AbstractRememberMeServices的“ key”属性。应该设置为唯一值,以确保“记住我的 Cookie”仅在一个应用程序[24]中有效。如果未设置,将生成一个安全的随机值。由于生成安全的随机值可能需要一段时间,因此,在使用“记住我”功能时,显式设置该值有助于缩短启动时间。

  • services-alias 将内部定义的RememberMeServices导出为 Bean 别名,从而允许其他 Bean 在应用程序上下文中使用。

  • services-ref 允许完全控制过滤器将使用的RememberMeServices实现。该值应该是实现此接口的应用程序上下文中 Bean 的id。如果正在使用注销过滤器,则还应实现LogoutHandler

  • token-repository-ref 配置PersistentTokenBasedRememberMeServices,但允许使用自定义的PersistentTokenRepository bean。

  • token-validity-seconds Map 到AbstractRememberMeServicestokenValiditySeconds属性。指定“记住我的 cookie”有效的时间段(以秒为单位)。默认情况下,有效期为 14 天。

  • use-secure-cookie 建议仅通过 HTTPS 提交“记住我” cookie,因此应将其标记为“安全”。默认情况下,如果发出登录请求的连接是安全的(应该是安全的),则将使用安全 cookie。如果将此属性设置为false,将不使用安全 cookie。将其设置为true将始终在 cookie 上设置安全标志。此属性 Map 到AbstractRememberMeServicesuseSecureCookie属性。

  • user-service-ref 记住我的服务实现需要访问UserDetailsService,因此在应用程序上下文中必须定义一个。如果只有一个,它将由名称空间配置自动选择和使用。如果有多个实例,则可以使用此属性显式指定 Bean id

<request-cache> Element

设置RequestCache实例,ExceptionTranslationFilter将在调用AuthenticationEntryPoint之前将其用于存储请求信息。

<request-cache>的父元素
<request-cache> Attributes

  • ref 定义对RequestCache的 Spring bean 的引用。

<session-management>

与会话 Management 相关的功能是通过在过滤器堆栈中添加SessionManagementFilter来实现的。

<session-management>的父元素
<session-management> Attributes

  • invalid-session-url 设置此属性将为SessionManagementFilter注入使用该属性值配置的SimpleRedirectInvalidSessionStrategy。提交无效的会话 ID 后,将调用该策略,并重定向到配置的 URL。

  • invalid-session-url 允许注入由 SessionManagementFilter 使用的 InvalidSessionStrategy 实例。使用此属性或invalid-session-url属性,但不能同时使用。

  • session-authentication-error-url 定义错误页面的 URL,当 SessionAuthenticationStrategy 引发异常时应显示该页面。如果未设置,则将未经授权的(401)错误代码返回给 Client 端。请注意,如果在基于表单的登录过程中发生错误,则该属性将不适用,其中,身份验证失败的 URL 将优先。

  • session-authentication-strategy-ref **允许注入由 SessionManagementFilter 使用的 SessionAuthenticationStrategy 实例

  • session-fixation-protection 指示用户认证时如何应用会话固定保护。如果设置为“ none”,则不会应用任何保护。 “ newSession”将创建一个新的空会话,仅迁移与 Spring Security 相关的属性。 “ migrateSession”将创建一个新会话,并将所有会话属性复制到新会话。在 Servlet 3.1(Java EE 7)和更高版本的容器中,指定“ changeSessionId”将保留现有会话,并使用容器提供的会话固定保护(HttpServletRequest#changeSessionId())。在 Servlet 3.1 和更高版本的容器中,默认值为“ changeSessionId”;在较旧的容器中,默认值为“ migrateSession”。如果在较旧的容器中使用“ changeSessionId”,则会引发异常。

如果启用了会话固定保护,则为SessionManagementFilter注入适当配置的DefaultSessionAuthenticationStrategy。有关更多详细信息,请参见此类的 Javadoc。

<session-management>的子元素

<concurrency-control>

增加了对并发会话控制的支持,从而可以限制用户可以拥有的活动会话的数量。将创建一个ConcurrentSessionFilter,并将一个ConcurrentSessionControlAuthenticationStrategySessionManagementFilter一起使用。如果已声明form-login元素,则策略对象也将注入到创建的身份验证过滤器中。将创建SessionRegistry的实例(除非用户希望使用自定义 bean,否则为SessionRegistryImpl实例)供策略使用。

<concurrency-control>的父元素
<concurrency-control> Attributes

  • 如果超过最大错误 如果设置为“ true”,则当用户尝试超过允许的最大会话数时,将引发SessionAuthenticationException。默认行为是使原始会话到期。

  • expired-url 如果用户尝试使用并发会话控制器“已过期”的会话,则该用户将被重定向到该 URL,因为该用户超过了允许的会话数,并且已在其他地方再次登录。除非设置exception-if-maximum-exceeded,否则应设置。如果未提供任何值,则到期消息将直接写回到响应中。

  • expired-url 允许注入 ConcurrentSessionFilter 使用的 ExpiredSessionStrategy 实例

  • max-sessions Map 到ConcurrentSessionControlAuthenticationStrategymaximumSessions属性。将-1指定为支持无限会话的值。

  • session-registry-alias 引用内部会话注册表以在您自己的 bean 或 Management 界面中使用也很有用。您可以使用session-registry-alias属性公开内部 bean,为其提供一个名称,您可以在配置中的其他位置使用它。

  • session-registry-ref 用户可以使用session-registry-ref属性提供自己的SessionRegistry实现。其他并发会话控制 bean 将被连接起来以使用它。

<x509>

添加了对 X.509 身份验证的支持。 X509AuthenticationFilter将添加到堆栈中,并且将创建Http403ForbiddenEntryPoint bean。仅当没有其他身份验证机制在使用时才使用后者(其唯一功能是返回 HTTP 403 错误代码)。还将创建一个PreAuthenticatedAuthenticationProvider,将PreAuthenticatedAuthenticationProvider的用户权限加载委托给UserDetailsService

<x509>的父元素
<x509> Attributes

  • authentication-details-source-refAuthenticationDetailsSource的引用

  • subject-principal-regex 定义一个正则表达式,该正则表达式将用于从证书中提取用户名(用于UserDetailsService)。

  • user-service-ref 如果配置了多个实例,则允许将特定的UserDetailsService与 X.509 一起使用。如果未设置,将尝试自动查找并使用合适的实例。

<filter-chain-map>

用于通过 FilterChainMap 显式配置 FilterChainProxy 实例

<filter-chain-map> Attributes

  • request-matcher 定义用于匹配传入请求的策略。当前,选项为“ ant”(用于 ant 路径模式),“ regex”用于正则表达式,“ ciRegex”用于不区分大小写的正则表达式。
<filter-chain-map>的子元素

<filter-chain>

用于定义一个特定的 URL 模式和适用于与该模式匹配的 URL 的过滤器列表。当将多个过滤器链元素组合到一个列表中以配置 FilterChainProxy 时,必须将最特定的模式放在列表的顶部,而将最常规的模式放在底部。

<filter-chain>的父元素
<filter-chain> Attributes

  • 过滤器 逗号分隔的实现Filter的 Spring bean 引用列表。值“ none”表示此FilterChain不应使用Filter

  • request-matcher-refRequestMatcher的引用,该引用将用于确定是否应调用filters属性中的任何Filter

<filter-security-metadata-source>

用于显式配置 FilterSecurityMetadataSource bean 与 FilterSecurityInterceptor 一起使用。通常仅在显式配置 FilterChainProxy 而不是使用\ 元素时才需要。使用的拦截 URL 元素应仅包含模式,方法和访问属性。其他任何情况都将导致配置错误。

<filter-security-metadata-source> Attributes

  • id Bean 标识符,用于引用上下文中其他位置的 Bean。

  • request-matcher 定义用于匹配传入请求的策略。当前,选项为“ ant”(用于 ant 路径模式),“ regex”用于正则表达式,“ ciRegex”用于不区分大小写的正则表达式。

  • use-expressions 允许在\ 元素的'access'属性中使用表达式,而不是在传统的配置属性列表中使用。默认为“ true”。如果启用,则每个属性应包含一个布尔表达式。如果表达式的计算结果为“ true”,则将授予访问权限。
<filter-security-metadata-source>的子元素

15.2.2 WebSocket 安全

Spring Security 4.0 提供了对消息授权的支持。一个有用的具体示例是在基于 WebSocket 的应用程序中提供授权。

<websocket-message-broker>

websocket-message-broker 元素具有两种不同的模式。如果未指定[email protected],它将执行以下操作:

  • 确保任何 SimpAnnotationMethodMessageHandler 都将 AuthenticationPrincipalArgumentResolver 注册为自定义参数解析器。这允许使用@AuthenticationPrincipal来解析当前Authentication的主体

  • 确保为 clientInboundChannel 自动注册了 SecurityContextChannelInterceptor。这将使用 Message 中找到的用户填充 SecurityContextHolder

  • 确保 ChannelSecurityInterceptor 已向 clientInboundChannel 注册。这允许为消息指定授权规则。

  • 确保 CsrfChannelInterceptor 已向 clientInboundChannel 注册。这样可以确保仅启用来自原始域的请求。

  • 确保已向 WebSocketHttpRequestHandler,TransportHandlingSockJsService 或 DefaultSockJsService 注册了 CsrfTokenHandshakeInterceptor。这样可以确保将来自 HttpServletRequest 的预期 CsrfToken 复制到 WebSocket 会话属性中。

如果需要其他控制,则可以指定 ID,并将 ChannelSecurityInterceptor 分配给指定的 ID。然后,可以手动完成与 Spring 的消息传递基础结构的所有连接。这比较麻烦,但是可以更好地控制配置。

<websocket-message-broker> Attributes

  • id 一个 bean 标识符,用于引用上下文中其他地方的 ChannelSecurityInterceptor bean。如果指定,Spring Security 需要在 Spring Messaging 中进行显式配置。如果未指定,Spring Security 将按照名为“<websocket-message-broker>”的部分中的说明自动与消息传递基础结构集成。

  • same-origin-disabled 禁用对 StompHeaders 中存在 CSRF 令牌的要求(默认为 false)。如果需要允许其他来源构建 SockJS 连接,则更改默认值很有用。
<websocket-message-broker>的子元素

<intercept-message>

定义消息的授权规则。

<intercept-message>的父元素
<intercept-message> Attributes

  • pattern 基于 ant 的模式,在 Message 目标上匹配。例如,“/ ”将任何消息与目标匹配; “/admin/ ”与目标以“/admin/**”开头的任何消息匹配。

  • 类型 要匹配的消息类型。有效值在 SimpMessageType 中定义(即 CONNECT,CONNECT_ACK,HEARTBEAT,MESSAGE,SUBSCRIBE,UNSUBSCRIBE,DISCONNECT,DISCONNECT_ACK,OTHER)。

  • access 用于保护消息的表达式。例如,“ denyAll”将拒绝访问所有匹配的消息; “ permitAll”将授予对所有匹配消息的访问权限; “ hasRole('ADMIN')要求当前用户具有匹配消息的角色'ROLE_ADMIN'。

15.2.3 身份验证服务

在 Spring Security 3.0 之前,AuthenticationManager是在内部自动注册的。现在,您必须使用<authentication-manager>元素显式注册一个。这将创建 Spring Security 的ProviderManager类的实例,该实例需要配置一个或多个AuthenticationProvider实例的列表。这些可以使用命名空间提供的语法元素创建,也可以是标准 Bean 定义,并使用authentication-provider元素标记为要添加到列表中。

<authentication-manager>

每个使用名称空间的 Spring Security 应用程序都必须在某处包含此元素。它负责注册为应用程序提供身份验证服务的AuthenticationManager。所有创建AuthenticationProvider实例的元素都应该是该元素的子元素。

<authentication-manager> Attributes

  • alias 该属性允许您为内部实例定义别名,以用于您自己的配置。 namespace introduction中描述了其用法。

  • erase-credentials 如果设置为 true,则在用户通过身份验证后,AuthenticationManager 将尝试清除返回的 Authentication 对象中的所有凭据数据。从字面上看,它 Map 到ProviderManagereraseCredentialsAfterAuthentication属性。 Core Services一章对此进行了讨论。

  • id 此属性使您可以定义内部实例的 ID,以供您在自己的配置中使用。它与 alias 元素相同,但是使用 id 属性的元素提供了更一致的体验。
<authentication-manager>的子元素

<authentication-provider>

除非与ref属性一起使用,否则此元素是配置DaoAuthenticationProvider的简写。 DaoAuthenticationProviderUserDetailsService加载用户信息,并将用户名/密码组合与登录时提供的值进行比较。可以通过使用可用的命名空间元素(jdbc-user-service或通过使用user-service-ref属性指向应用程序上下文中其他位置定义的 bean)来定义UserDetailsService实例。您可以在namespace introduction中找到这些变化的示例。

<authentication-provider>的父元素
<authentication-provider> Attributes

  • ref 定义对实现AuthenticationProvider的 Spring bean 的引用。

如果您已经编写了自己的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 对实现 UserDetailsService 的 bean 的引用,可以使用标准 bean 元素或自定义 user-service 元素创建该 bean。
<authentication-provider>的子元素

<jdbc-user-service>

导致创建基于 JDBC 的 UserDetailsService。

<jdbc-user-service> Attributes

  • authority-by-username-query 一种 SQL 语句,用于查询给定用户名的用户授予的权限。

默认是

select username, authority from authorities where username = ?

  • cache-ref 定义对与 UserDetailsService 一起使用的缓存的引用。

  • data-source-ref 提供所需表的 DataSource 的 Bean ID。

  • group-authorities-by-username-query 一个给定用户名的查询用户组权限的 SQL 语句。默认是
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”用于无前缀。

  • 用户按用户名查询 SQL 语句,用于查询给定用户名的用户名,密码和启用状态。默认是
select username, password, enabled from users where username = ?

<password-encoder>

可以将验证提供程序配置为使用namespace introduction中所述的密码编码器。这将导致使用适当的PasswordEncoder实例注入 Bean。

<password-encoder>的父元素
<password-encoder> Attributes

  • hash 定义用于用户密码的哈希算法。我们强烈建议您不要使用 MD4,因为它是一种非常弱的哈希算法。

  • ref 定义对实现PasswordEncoder的 Spring bean 的引用。

<user-service>

从属性文件或“用户”子元素列表创建内存 UserDetailsService。用户名在内部会转换为小写形式,以允许不区分大小写的查找,因此如果需要区分大小写,则不应使用此名称。

<user-service> Attributes

  • id Bean 标识符,用于引用上下文中其他位置的 Bean。

  • properties 属性文件的位置,其中每一行的格式为
username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]
<user-service>的子元素

<user>

代表应用程序中的用户。

<user>的父元素
<user> Attributes

  • 授权 授予用户的其他授权之一。用逗号隔开(但不能有空格)。例如,“ ROLE_USER,ROLE_ADMINISTRATOR”

  • 已禁用 可以设置为“ true”以将帐户标记为已禁用和不可用。

  • 已锁定 可以设置为“ true”以将帐户标记为已锁定且无法使用。

  • name 分配给用户的用户名。

  • 密码 分配给用户的密码。如果相应的身份验证提供程序支持哈希(请记住要设置“ user-service”元素的“ hash”属性),则可以对此进行哈希处理。在数据将不用于认证而仅用于访问权限的情况下,将忽略此属性。如果省略,则名称空间将生成一个随机值,以防止其偶然用于身份验证。不能为空。

15.2.4 方法安全性

<global-method-security>

该元素是添加对 Spring Security bean 上的安全方法的支持的主要方法。可以使用 AspectJ 语法通过使用 Comments(在接口或类级别定义)或将一组切入点定义为子元素来保护方法。

<global-method-security> Attributes

  • access-decision-manager-ref 方法安全性使用与 Web 安全性相同的AccessDecisionManager配置,但是可以使用此属性来覆盖它。默认情况下,AffirmativeBased 实现与 RoleVoter 和 AuthenticatedVoter 一起使用。

  • authentication-manager-ref 对用于方法安全性的AuthenticationManager的引用。

  • jsr250-annotations 指定是否要使用 JSR-250 样式属性(例如“ RolesAllowed”)。这将需要 classpath 上的 javax.annotation.security 类。将其设置为 true 还会在AccessDecisionManager上添加Jsr250Voter,因此,如果您要使用自定义实现并希望使用这些注解,则需要确保执行此操作。

  • metadata-source-ref 可以提供一个外部MethodSecurityMetadataSource实例,该实例的优先级高于其他来源(例如默认 Comments)。

  • mode 该属性可以设置为“ aspectj”以指定应该使用 AspectJ 而不是默认的 Spring AOP。安全方法必须与spring-security-aspects模块中的AnnotationSecurityAspect编织在一起。

重要的是要注意,AspectJ 遵循 Java 的规则,即不继承接口上的 Comments。这意味着在接口上定义安全性 Comments 的方法将不安全。相反,在使用 AspectJ 时,必须在类上放置 Security 注解。

  • order 允许为方法安全拦截器设置建议“ order”。

  • pre-post-annotations 指定是否应为此应用程序上下文启用 Spring Security 的调用前后 Comments(@ PreFilter,@ PreAuthorize,@ PostFilter,@ PostAuthorize)。默认为“禁用”。

  • proxy-target-class 如果为 true,则将使用基于类的代理而不是基于接口的代理。

  • run-as-manager-ref 对配置的MethodSecurityInterceptor将使用的可选RunAsManager实现的引用

  • secured-annotations 指定是否应为此应用程序上下文启用 Spring Security 的@SecuredComments。默认为“禁用”。
<global-method-security>的子元素

<after-invocation-provider>

此元素可用于装饰AfterInvocationProvider,以供<global-method-security>名称空间维护的安全拦截器使用。您可以在global-method-security元素中定义零个或多个,每个都具有ref属性,该属性指向应用程序上下文中的AfterInvocationProvider bean 实例。

<after-invocation-provider>的父元素
<after-invocation-provider> Attributes

  • ref 定义对实现AfterInvocationProvider的 Spring bean 的引用。

<pre-post-annotation-handling>

允许完全替换基于默认表达式的机制来处理 Spring Security 的调用前后 Comments(@ PreFilter,@ PreAuthorize,@ PostFilter,@ PostAuthorize)。仅在启用这些 Comments 的情况下适用。

<pre-post-annotation-handling>的父元素
<pre-post-annotation-handling>的子元素

<invocation-attribute-factory>

定义 PrePostInvocationAttributeFactory 实例,该实例用于从带 Comments 的方法中生成调用前后的元数据。

<invocation-attribute-factory>的父元素
<invocation-attribute-factory> Attributes

  • ref 定义对 Spring bean ID 的引用。

<post-invocation-advice>

使用 ref 作为\ 元素的PostInvocationAuthorizationAdvice自定义PostInvocationAdviceProvider

<post-invocation-advice>的父元素
<post-invocation-advice> Attributes

  • ref 定义对 Spring bean ID 的引用。

<pre-invocation-advice>

使用 ref 作为\ 元素的PreInvocationAuthorizationAdviceVoter自定义PreInvocationAuthorizationAdviceVoter

<pre-invocation-advice>的父元素
<pre-invocation-advice> Attributes

  • ref 定义对 Spring bean ID 的引用。

使用以下方法保护方法

<protect-pointcut>而不是使用@SecuredComments 在单个方法或类的基础上定义安全属性,而是可以使用<protect-pointcut>元素跨服务层中的整个方法和接口集定义跨领域安全约束。您可以在namespace introduction中找到示例。

<protect-pointcut>的父元素
<protect-pointcut> Attributes

  • 访问 访问配置属性列表,适用于与切入点匹配的所有方法,例如“ ROLE_A,ROLE_B”

  • 表达式 一个 AspectJ 表达式,包括'execution'关键字。例如,“ execution(int com.foo.TargetObject.countLength(String))”(不带引号)。

<intercept-methods>

可以在 bean 定义内使用,以向 bean 添加安全拦截器并为 bean 的方法设置访问配置属性

<intercept-methods> Attributes

  • access-decision-manager-ref **被创建的方法安全拦截器使用的可选 AccessDecisionManager bean ID。
<intercept-methods>的子元素

<method-security-metadata-source>

创建一个 MethodSecurityMetadataSource 实例

<method-security-metadata-source> Attributes

  • id Bean 标识符,用于引用上下文中其他位置的 Bean。

  • use-expressions 允许在\ 元素的'access'属性中使用表达式,而不是在传统的配置属性列表中使用。默认为“假”。如果启用,则每个属性应包含一个布尔表达式。如果表达式的计算结果为“ true”,则将授予访问权限。
<method-security-metadata-source>的子元素

<protect>

定义一个受保护的方法以及适用于该方法的访问控制配置属性。强烈建议您不要将“保护”声明与“全局方法安全性”提供的任何服务混合使用。

<protect>的父元素
<protect> Attributes

  • access 适用于该方法的访问配置属性列表,例如“ ROLE_A,ROLE_B”。

  • 方法 方法名称

15.2.5 LDAP 命名空间选项

自己的章节中详细介绍了 LDAP。我们将在这里扩展它,并提供一些有关名称空间选项如何 Map 到 Spring Bean 的解释。 LDAP 实现广泛使用 Spring LDAP,因此熟悉该项目的 API 可能会有用。

使用以下命令定义 LDAP 服务器

<ldap-server>元素此元素设置一个供其他 LDAP Bean 使用的 Spring LDAP ContextSource,以定义 LDAP 服务器的位置以及用于与其连接的其他信息(例如用户名和密码,如果不允许匿名访问)。它还可以用于创建嵌入式服务器以进行测试。 LDAP chapter涵盖了这两个选项的语法详细信息。实际的ContextSource实现是DefaultSpringSecurityContextSource,它扩展了 Spring LDAP 的LdapContextSource类。 manager-dnmanager-password属性分别 Map 到后者的userDnpassword属性。

如果在应用程序上下文中仅定义了一个服务器,则其他 LDAP 名称空间定义的 Bean 将自动使用它。否则,您可以为元素赋予“ id”属性,并使用server-ref属性从其他名称空间 bean 引用该元素。如果要在其他传统的 Spring Bean 中使用它,则实际上是ContextSource实例的 Bean id

<ldap-server> Attributes

  • id Bean 标识符,用于引用上下文中其他位置的 Bean。

  • ldif 明确指定要加载到嵌入式 LDAP 服务器中的 ldif 文件资源。 ldiff 应该是一个 Spring 资源模式(即 classpath:init.ldiff)。默认值为 classpath 。ldiff

  • manager-dn “ manager”用户身份的用户名(DN),将用于向(非嵌入式)LDAP 服务器进行身份验证。如果省略,将使用匿名访问。

  • manager-password ManagerDN 的密码。如果指定了 manager-dn,则这是必需的。

  • 端口 指定 IP 端口号。例如,用于配置嵌入式 LDAP 服务器。默认值为 33389.

  • root 嵌入式 LDAP 服务器的可选根后缀。默认值为“ dc = springframework,dc = org”

  • url 在不使用嵌入式 LDAP 服务器时指定 ldap 服务器 URL。

<ldap-authentication-provider>

此元素是创建LdapAuthenticationProvider实例的简写。默认情况下,它将使用BindAuthenticator实例和DefaultAuthoritiesPopulator配置。与所有名称空间身份验证提供程序一样,它必须作为authentication-provider元素的子元素包括在内。

<ldap-authentication-provider>的父元素
<ldap-authentication-provider> Attributes

  • group-role-attribute LDAP 属性名称,其中包含将在 Spring Security 中使用的角色名称。Map 到DefaultLdapAuthoritiesPopulatorgroupRoleAttribute属性。默认为“ cn”。

  • group-search-base 群组成员资格搜索的搜索基础。Map 到DefaultLdapAuthoritiesPopulatorgroupSearchBase构造函数参数。默认为“”(从根目录搜索)。

  • group-search-filter 群组搜索过滤器。Map 到DefaultLdapAuthoritiesPopulatorgroupSearchFilter属性。默认为(uniqueMember ={0})。替换的参数是用户的 DN。

  • role-prefix 一个非空字符串前缀,将添加到从持久性加载的角色字符串中。Map 到DefaultLdapAuthoritiesPopulatorrolePrefix属性。默认为“ ROLE_”。在默认值为非空的情况下,将值“ none”用于无前缀。

  • server-ref 要使用的可选服务器。如果省略,并且注册了默认的 LDAP 服务器(使用 ,没有 ID),则将使用该服务器。

  • user-context-mapper-ref 允许通过指定 UserDetailsContextMapper bean 来显式自定义已加载的用户对象,该 bean 将与用户目录条目中的上下文信息一起调用

  • user-details-class 允许指定用户条目的 objectClass。如果设置,框架将尝试将已定义类的标准属性加载到返回的 UserDetails 对象中

  • user-dn-pattern 如果用户位于目录中的固定位置(即,您可以直接从用户名计算 DN,而无需执行目录搜索),则可以使用此属性直接 Map 到 DN 。它直接 Map 到AbstractLdapAuthenticatoruserDnPatterns属性。该值是用于构建用户 DN 的特定模式,例如“ uid ={0},ou = people”。键“{0}”必须存在,并将被用户名替换。

  • 用户搜索基础 用户搜索的搜索基础。默认为“”。仅与“用户搜索过滤器”一起使用。

如果需要执行搜索以在目录中找到用户,则可以设置这些属性来控制搜索。 BindAuthenticator将配置为FilterBasedLdapUserSearch,并且属性值直接 Map 到该 bean 的构造函数的前两个参数。如果未设置这些属性,并且没有提供user-dn-pattern作为替代,那么将使用user-search-filter="(uid={0})"user-search-base=""的默认搜索值。

  • user-search-filter 用于搜索用户的 LDAP 过滤器(可选)。例如“(uid ={0})”。替换的参数是用户的登录名。

如果需要执行搜索以在目录中找到用户,则可以设置这些属性来控制搜索。 BindAuthenticator将配置为FilterBasedLdapUserSearch,并且属性值直接 Map 到该 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> Attributes

  • hash 定义用于用户密码的哈希算法。我们强烈建议您不要使用 MD4,因为它是一种非常弱的哈希算法。

  • password-attribute 包含用户密码的目录中的属性。默认为“ userPassword”。
<password-compare>的子元素

<ldap-user-service>

该元素配置 LDAP UserDetailsService。所使用的类是LdapUserDetailsService,它是FilterBasedLdapUserSearchDefaultLdapAuthoritiesPopulator的组合。它支持的属性与<ldap-provider>中的用法相同。

<ldap-user-service> Attributes

  • 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),则将使用该服务器。

  • user-context-mapper-ref 允许通过指定 UserDetailsContextMapper bean 来显式自定义已加载的用户对象,该 bean 将与用户目录条目中的上下文信息一起调用

  • user-details-class 允许指定用户条目的 objectClass。如果设置,框架将尝试将已定义类的标准属性加载到返回的 UserDetails 对象中

  • 用户搜索基础 用户搜索的搜索基础。默认为“”。仅与“用户搜索过滤器”一起使用。

  • user-search-filter 用于搜索用户的 LDAP 过滤器(可选)。例如“(uid ={0})”。替换的参数是用户的登录名。

15.3 Spring 安全性依赖性

本附录提供了 Spring Security 中的模块以及它们在运行中的应用程序中运行所需的其他依赖项的参考。我们不包括仅在构建或测试 Spring Security 本身时使用的依赖项。我们也没有包括外部依赖项所要求的传递性依赖项。

项目网站上列出了所需的 Spring 版本,因此下面的 Spring 依赖项省略了特定版本。请注意,Spring 应用程序中的其他非安全功能可能仍需要下面列出为“可选”的某些依赖项。此外,如果大多数应用程序中都使用了列为“可选”的依赖项,则在项目的 Maven POM 文件中可能实际上并未将其标记为此类依赖项。除非您使用指定的功能,否则它们仅在不需要它们的意义上是“可选的”。

在模块依赖于另一个 Spring Security 模块的情况下,也假定该模块所依赖的模块的非可选依赖关系是必需的,因此未单独列出。

15.3.1 spring-security-core

使用 Spring Security 的任何项目中都必须包含核心模块。

表 15.1 核心依赖

DependencyVersionDescription
ehcache1.6.2如果使用基于 Ehcache 的用户缓存实现,则为必需(可选)。
spring-aop 方法安全性基于 Spring AOP
spring-beans Spring 配置必需
spring-expression 基于表达式的方法安全性必需(可选)
spring-jdbc 如果使用数据库存储用户数据,则为必需(可选)。
spring-tx 如果使用数据库存储用户数据,则为必需(可选)。
aspectjrt1.6.10如果使用 AspectJ 支持,则为必需(可选)。
jsr250-api1.0如果您使用的是 JSR-250 方法安全性 Comments(可选),则为必需。

15.3.2 spring-security-remoting

使用 Servlet API 的 Web 应用程序通常需要此模块。

表 15.2 远程依赖

DependencyVersionDescription
spring-security-core
spring-web 使用 HTTP 远程支持的 Client 端需要。

15.3.3 spring-security-web

使用 Servlet API 的 Web 应用程序通常需要此模块。

表 15.3 网络依赖

DependencyVersionDescription
spring-security-core
spring-web Spring Web 支持类被广泛使用。
spring-jdbc 对于基于 JDBC 的永久性“记住我”令牌存储库是必需的(可选)。
spring-tx “记住我”持久令牌存储库实现必需(可选)。

15.3.4 spring-security-ldap

仅在使用 LDAP 身份验证时才需要此模块。

表 15.4. LDAP 依赖关系

DependencyVersionDescription
spring-security-core
spring-ldap-core1.3.0LDAP 支持基于 Spring LDAP。
spring-tx 数据异常类是必需的。
apache-ds [1]1.5.5如果您使用嵌入式 LDAP 服务器(可选),则为必需。
shared-ldap0.9.15如果您使用嵌入式 LDAP 服务器(可选),则为必需。
ldapsdk4.1Mozilla LdapSDK。例如,如果您在 OpenLDAP 中使用密码策略功能,则用于解码 LDAP 密码策略控件。
[1]需要模块apacheds-coreapacheds-core-entryapacheds-protocol-sharedapacheds-protocol-ldapapacheds-server-jndi

15.3.5 spring-security-config

如果您使用的是 Spring Security 名称空间配置,那么此模块是必需的。

表 15.5. 配置依赖项

DependencyVersionDescription
spring-security-core
spring-security-web 如果使用任何与 Web 相关的名称空间配置,则为必需(可选)。
spring-security-ldap 如果使用 LDAP 名称空间选项(可选),则为必需。
spring-security-openid 如果使用的是 OpenID 身份验证,则为必需(可选)。
aspectjweaver1.6.10如果使用 protect-pointcut 名称空间语法(必需),则为必需。

15.3.6 spring-security-acl

ACL 模块。

表 15.6. ACL 依赖项

DependencyVersionDescription
spring-security-core
ehcache1.6.2如果使用基于 Ehcache 的 ACL 缓存实现,则为必需(如果使用自己的实现,则为可选)。
spring-jdbc 如果使用的是默认的基于 JDBC 的 AclService,则为必需(如果实现自己的,则为可选)。
spring-tx 如果使用的是默认的基于 JDBC 的 AclService,则为必需(如果实现自己的,则为可选)。

15.3.7 spring-security-cas

CAS 模块提供与 JA-SIG CAS 的集成。

表 15.7. CAS 依赖性

DependencyVersionDescription
spring-security-core
spring-security-web
cas-client-core3.1.12JA-SIG CASClient 端。这是 Spring Security 集成的基础。
ehcache1.6.2如果您正在使用基于 Ehcache 的票证缓存(可选),则为必需。

15.3.8 spring-security-openid

OpenID 模块。

表 15.8. OpenID 依赖项

DependencyVersionDescription
spring-security-core
spring-security-web
openid4java-nodeps0.9.6Spring Security 的 OpenID 集成使用 OpenID4Java。
httpclient4.1.1openid4java-nodeps 取决于 HttpClient 4.
guice2.0openid4java-nodeps 取决于 Guice 2.

15.3.9 spring-security-taglibs

提供 Spring Security 的 JSP 标签实现。

表 15.9. Taglib 依赖项

DependencyVersionDescription
spring-security-core
spring-security-web
spring-security-acl 如果您将accesscontrollist标记或hasPermission()表达式与 ACL 一起使用,则为必填项(可选)。
spring-expression 如果在标记访问约束中使用 SPEL 表达式,则为必需。

15.4 代理服务器配置

使用代理服务器时,确保已正确配置应用程序很重要。例如,许多应用程序将具有一个负载平衡器,该负载平衡器通过将请求转发到http://192.168.1:8080处的应用服务器来响应对https://example.com/的请求,如果没有适当的配置,则应用服务器将不知道负载平衡器是否存在并将该请求视为http://192.168.1:8080被处理由 Client。

要解决此问题,您可以使用RFC 7239来指定正在使用负载平衡器。为了使应用程序意识到这一点,您需要配置应用程序服务器以了解 X-ForwardedHeaders。例如,Tomcat 使用RemoteIpValve,而 Jetty 使用ForwardedRequestCustomizer。另外,Spring 4.3 用户可以使用ForwardedHeaderFilter

15.5 Spring Security 常见问题解答

15.5.1 一般问题

Spring Security 会满足我所有的应用程序安全要求吗?

Spring Security 为您的身份验证和授权要求提供了一个非常灵活的框架,但是在构建安全应用程序时,还有许多其他注意事项。 Web 应用程序容易受到各种您应该熟悉的攻击的攻击,最好在开始开发之前就进行攻击,因此您可以从一开始就牢记这些内容进行设计和编码。请访问 http://www.owasp.org/[OWASP 网站],以获取有关 Web 应用程序开发人员面临的主要问题的信息,以及可以针对他们采取的对策。

为什么不只使用 web.xml 安全性?

假设您正在基于 Spring 开发企业应用程序。通常需要解决四个安全问题:身份验证,Web 请求安全性,服务层安全性(即,实现业务逻辑的方法)和域对象实例安全性(即不同的域对象具有不同的权限)。牢记以下典型要求:

    • Authentication *:Servlet 规范提供了一种身份验证方法。但是,您将需要配置容器以执行身份验证,这通常需要编辑特定于容器的“领域”设置。这将导致不可移植的配置,如果您需要编写实际的 Java 类来实现容器的身份验证接口,则它甚至变得更加不可移植。借助 Spring Security,您可以实现完全的可移植性-直至 WAR 级别。此外,Spring Security 还提供了经过生产验证的身份验证提供程序和机制,供您选择,这意味着您可以在部署时切换身份验证方法。对于编写需要在未知目标环境中工作的产品的软件供应商而言,这尤其有价值。
  • Web 请求安全性:Servlet 规范提供了一种保护请求 URI 的方法。但是,这些 URI 只能以 Servlet 规范自己的受限 URI 路径格式表示。 Spring Security 提供了一种更为全面的方法。例如,您可以使用 Ant 路径或正则表达式,可以考虑 URI 的部分,而不仅仅是请求的页面(例如,可以考虑 HTTP GET 参数),并且可以实现自己的配置数据的运行时源。这意味着您的 Web 请求安全性可以在 Webapp 的实际执行过程中动态更改。

  • 服务层和域对象安全性: Servlet 规范中缺少对服务层安全性或域对象实例安全性的支持,这表示对多层应用程序的严重限制。通常,开发人员要么忽略这些要求,要么在其 MVC 控制器代码中实现安全逻辑(或者更糟的是在视图内部)。这种方法有严重的缺点:

  • *关注点分离:*授权是贯穿各领域的关注点,应照此实施。 MVC 控制器或实现授权代码的视图使测试控制器和授权逻辑更加困难,调试更加困难,并且通常会导致代码重复。

    • *支持富 Client 端和 Web 服务:*如果最终必须支持其他 Client 端类型,则嵌入在 Web 层中的任何授权代码都是不可重用的。应该考虑到 Spring 远程 Export 商仅 Export 服务层 bean(而不是 MVC 控制器)。这样,授权逻辑需要位于服务层中以支持多种 Client 端类型。

    • 层问题: MVC 控制器或视图仅仅是错误的体系结构层,无法实现有关服务层方法或域对象实例的授权决策。尽管可以将主体传递到服务层以使其能够做出授权决策,但这样做会在每个服务层方法上引入一个附加参数。一种更优雅的方法是使用 ThreadLocal 来容纳 Principal,尽管这可能会增加开发时间,以至于仅使用专用的安全框架就变得更加经济(基于成本效益)。

    • *授权代码质量:*通常,在 Web 框架中,它们“使做正确的事更容易,而做错事更难”。安全框架是相同的,因为它们以抽象的方式设计用于多种用途。从头开始编写自己的授权代码不会提供框架会提供的“设计检查”,而且内部授权代码通常将缺乏广泛部署,同行评审和新版本带来的改进。

对于简单的应用程序,servlet 规范安全性可能就足够了。尽管在 Web 容器可移植性,配置要求,有限的 Web 请求安全性以及不存在的服务层和域对象实例安全性的上下文中进行考虑,但很清楚的是,为什么开发人员经常寻求替代解决方案。

需要哪些 Java 和 Spring Framework 版本?

Spring Security 3.0 和 3.1 至少需要 JDK 1.5,并且也至少需要 Spring 3.0.3. 理想情况下,您应该使用最新版本,以避免出现问题。

Spring Security 2.0.x 要求最低 JDK 版本为 1.4,并且是针对 Spring 2.0.x 构建的。它也应该与使用 Spring 2.5.x 的应用程序兼容。

我是 Spring Security 的新手,我需要构建一个支持通过 HTTPS 进行 CAS 单一登录的应用程序,同时允许本地对某些 URL 进行基本身份验证,并针对多个后端用户信息源(LDAP 和 JDBC)进行身份验证。我已经复制了一些找到的配置文件,但是它不起作用。

有什么事吗

或替代其他复杂方案...

实际上,您需要先了解要使用的技术,然后才能成功使用它们构建应用程序。安全性很复杂。使用登录表单来设置简单的配置,并使用 Spring Security 的命名空间来设置一些硬编码的用户是相当简单的。迁移到使用支持的 JDBC 数据库也很容易。但是,如果您尝试直接跳入这种复杂的部署方案,几乎肯定会感到沮丧。设置 CAS 之类的系统,配置 LDAP 服务器和正确安装 SSL 证书所需的学习曲线有很大的跳跃。因此,您需要一次采取一步。

从 Spring Security 的角度来看,您应该做的第一件事是遵循网站上的“入门”指南。这将带您完成一系列步骤,以启动并运行并了解框架的运行方式。如果使用的是您不熟悉的其他技术,则应进行一些研究,并尝试确保在将它们组合到复杂系统中之前可以单独使用它们。

15.5.2 常见问题

尝试登录时,收到一条错误消息,提示“凭据错误”。怎么了?

这意味着认证失败。它并没有说明原因,因为最好避免提供可能有助于攻击者猜测帐户名或密码的详细信息。

这也意味着,如果您在论坛中提出此问题,除非您提供其他信息,否则您将找不到答案。与任何问题一样,您应该检查调试日志的输出,注意所有异常堆栈跟踪和相关消息。在调试器中单步执行代码以查看身份验证失败的原因以及原因。编写一个测试案例,在应用程序外部练习您的身份验证配置。失败通常是由于数据库中存储的密码数据与用户 Importing 的密码数据不同。如果您使用的是哈希密码,请确保数据库中存储的值与应用程序中配置的PasswordEncoder完全相同。

当我尝试登录时,我的应用程序进入“无限循环”,这是怎么回事?

无限循环和重定向到登录页面的常见用户问题是由于不小心将登录页面配置为“安全”资源引起的。确保您的配置允许匿名访问登录页面,方法是将其从安全过滤器链中排除,或者将其标记为需要 ROLE_ANONYMOUS。

如果您的 AccessDecisionManager 包含 AuthenticatedVoter,则可以使用属性“ IS_AUTHENTICATED_ANONYMOUSLY”。如果您正在使用标准名称空间配置设置,则该选项自动可用。

从 Spring Security 2.0.1 开始,当您使用基于命名空间的配置时,将在加载应用程序上下文时进行检查,并在登录页面似乎受到保护的情况下记录警告消息。

我收到一条消息“访问被拒绝(用户是匿名用户);”的异常。怎么了?

这是一条调试级别的消息,它在匿名用户首次尝试访问受保护的资源时发生。

DEBUG [ExceptionTranslationFilter] - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.AccessDeniedException: Access is denied
at org.springframework.security.vote.AffirmativeBased.decide(AffirmativeBased.java:68)
at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:262)

这是正常现象,不必担心。

为什么即使我退出了应用程序,仍然可以看到受保护的页面?

造成这种情况的最常见原因是您的浏览器已经缓存了该页面,并且您看到的是从浏览器缓存中检索到的副本。通过检查浏览器是否确实在发送请求来验证这一点(检查服务器访问日志,调试日志或使用合适的浏览器调试插件,例如 Firefox 的“ Tamper Data”)。这与 Spring Security 无关,您应该配置应用程序或服务器以设置适当的Cache-Control响应头。请注意,永远不会缓存 SSL 请求。

我收到一条消息“在 SecurityContext 中找不到身份验证对象”的异常。怎么了?

这是另一条调试级别消息,该消息在匿名用户首次尝试访问受保护的资源时出现,但是在您的过滤器链配置中没有AnonymousAuthenticationFilter时出现。

DEBUG [ExceptionTranslationFilter] - Authentication exception occurred; redirecting to authentication entry point
org.springframework.security.AuthenticationCredentialsNotFoundException:
                            An Authentication object was not found in the SecurityContext
at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342)
at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254)

这是正常现象,不必担心。

我无法使用 LDAP 身份验证。

我的配置有什么问题?

请注意,LDAP 目录的权限通常不允许您读取用户密码。因此,通常无法使用“什么是 UserDetailsService,我需要一个吗?”部分,Spring Security 会将存储的密码与用户提交的密码进行比较。最常见的方法是使用 LDAP“ bind”,这是LDAP 协议支持的操作之一。通过这种方法,Spring Security 通过尝试以用户身份验证目录来验证密码。

LDAP 认证最常见的问题是缺乏对目录服务器树结构和配置的了解。不同公司的情况会有所不同,因此您必须自己找出来。在将 Spring Security LDAP 配置添加到应用程序之前,最好使用标准 Java LDAP 代码(不涉及 Spring Security)编写一个简单的测试,并确保您可以使其首先工作。例如,要验证用户身份,可以使用以下代码:

@Test
public void ldapAuthenticationIsSuccessful() throws Exception {
        Hashtable<String,String> env = new Hashtable<String,String>();
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, "cn=joe,ou=users,dc=mycompany,dc=com");
        env.put(Context.PROVIDER_URL, "ldap://mycompany.com:389/dc=mycompany,dc=com");
        env.put(Context.SECURITY_CREDENTIALS, "joespassword");
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

        InitialLdapContext ctx = new InitialLdapContext(env, null);

}

Session Management

会话 Management 问题是论坛问题的常见来源。如果要开发 Java Web 应用程序,则应了解如何在 servlet 容器和用户浏览器之间维护会话。您还应该了解安全和非安全 Cookie 的区别,以及使用 HTTP/HTTPS 以及在两者之间进行切换的含义。 Spring Security 与维护会话或提供会话标识符无关。这完全由 servlet 容器处理。

我正在使用 Spring Security 的并发会话控制来防止用户一次登录多次。

登录后打开另一个浏览器窗口时,它不会阻止我再次登录。为什么我可以多次登录?

浏览器通常每个浏览器实例维护一个会话。您不能一次有两个单独的会话。因此,如果您再次在另一个窗口或选项卡中登录,则仅在同一会话中重新进行身份验证。服务器对选项卡,窗口或浏览器实例一无所知。它所看到的只是 HTTP 请求,并根据它们所包含的 JSESSIONID cookie 的值将它们绑定到特定会话。当用户在会话期间进行身份验证时,Spring Security 的并发会话控件会检查他们拥有的“其他身份验证会话”的数量。如果它们已经通过同一会话进行了身份验证,则重新身份验证将无效。

通过 Spring Security 进行身份验证时,为什么会话 ID 会更改?

使用默认配置,Spring Security 在用户认证时更改会话 ID。如果您使用的是 Servlet 3.1 或更高版本的容器,则只需更改会话 ID。如果您使用的是较旧的容器,Spring Security 将使现有会话无效,创建一个新会话,并将会话数据传输到新会话。以这种方式改变会话标识符可以防止“会话固定”攻击。您可以在网上和参考手册中找到有关此内容的更多信息。

我正在使用 Tomcat(或其他一些 servlet 容器),并且已为登录页面启用 HTTPS,然后再切换回 HTTP。

它不起作用-经过身份验证后,我只能回到登录页面。

发生这种情况是因为在 HTTPS 下创建的会话(会话 cookie 标记为“安全”)无法随后在 HTTP 下使用。浏览器不会将 cookie 发送回服务器,并且任何会话状态都将丢失(包括安全上下文信息)。首先使用 HTTP 启动会话应该可以正常工作,因为会话 cookie 不会被标记为安全。但是,Spring Security 的会话固定保护会对此产生干扰,因为它会导致通常使用安全标志将新的会话 ID cookie 发送回用户的浏览器。要解决此问题,可以禁用会话固定保护,但是在较新的 Servlet 容器中,您还可以配置会话 cookie,使其从不使用安全标志。请注意,在 HTTP 和 HTTPS 之间切换通常不是一个好主意,因为任何完全使用 HTTP 的应用程序都容易受到中间人攻击。为了 true 安全,用户应开始使用 HTTPS 访问您的站点并 continue 使用它,直到注销为止。即使从通过 HTTP 访问的页面上单击 HTTPS 链接也可能存在风险。如果您需要更多说服力,请查看sslstrip之类的工具。

我没有在 HTTP 和 HTTPS 之间切换,但是我的会话仍然丢失

通过交换会话 cookie 或向 URL 添加jsessionid参数来维护会话(如果使用 JSTL 输出 URL 或在 URL 上调用HttpServletResponse.encodeUrl(例如,在重定向之前),则会自动发生)。禁用,并且您不重写 URL 来包含jsessionid,则会话将丢失。请注意,出于安全原因,首选使用 cookie,因为它不会在 URL 中公开会话信息。

我正在尝试使用并发会话控制支持,但是即使我确定我已经注销并且没有超出允许的会话,它也不允许我重新登录。

确保已将侦听器添加到 web.xml 文件。必须确保在会话被销毁时通知 Spring Security 会话注册表。没有它,会话信息将不会从注册表中删除。

<listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>

Spring Security 通过将 create-session 属性设置为 never,即使在未配置会话的情况下也可以创建会话。

这通常意味着用户的应用程序正在某个地方创建会话,但是他们不知道该会话。最常见的罪魁祸首是 JSP。许多人并不知道 JSP 默认情况下会创建会话。为了防止 JSP 创建会话,请将指令<%@ page session="false" %>添加到页面顶部。

如果无法确定要在何处创建会话,可以添加一些调试代码来跟踪位置。一种方法是将javax.servlet.http.HttpSessionListener添加到您的应用程序,该应用程序在sessionCreated方法中调用Thread.dumpStack()

执行 POST 时收到 403 禁止

如果为 HTTP POST 返回了 HTTP 403 Forbidden,但对于 HTTP GET 适用,则该问题很可能与CSRF有关。提供 CSRF 令牌或禁用 CSRF 保护(不建议)。

我正在使用 RequestDispatcher 将请求转发到另一个 URL,但是没有应用我的安全约束。

过滤器默认情况下不应用于转发或包含。如果您确实希望将安全过滤器应用于转发和/或包含,则必须使用\ 元素( 的子元素)在 web.xml 中显式配置这些过滤器。

我已经在应用程序上下文中添加了 Spring Security 的\ 元素,但是如果我在 Spring MVC 控制器 bean(Struts 操作等)中添加了安全 Comments,那么它们似乎没有作用。

在 Spring Web 应用程序中,保存用于调度程序 Servlet 的 Spring MVC bean 的应用程序上下文通常与主应用程序上下文分开。它通常在名为myapp-servlet.xml的文件中定义,其中“ myapp”是在web.xml中分配给 Spring DispatcherServlet的名称。一个应用程序可以有多个DispatcherServlet,每个都有自己的隔离应用程序上下文。这些“子”上下文中的 Bean 对应用程序的其余部分不可见。 “父”应用程序上下文由您在web.xml中定义的ContextLoaderListener加载,并且对所有子上下文可见。通常在此父上下文中定义安全配置(包括<global-method-security>元素)。结果,由于无法从DispatcherServlet上下文中看到 Bean,因此不会强制应用到这些 Web Bean 中的方法的任何安全性约束。您需要将<global-method-security>声明移至 Web 上下文,或将要保护的 Bean 移至主应用程序上下文。

通常,我们建议在服务层而不是单个 Web 控制器上应用方法安全性。

我有一个已经通过身份验证的用户,但是当我在某些请求期间尝试访问 SecurityContextHolder 时,Authentication 为 null。

为什么看不到用户信息?

如果使用与 URL 模式匹配的<intercept-url>元素中的属性filters='none'从安全过滤器链中排除了该请求,则不会为该请求填充SecurityContextHolder。检查调试日志以查看请求是否正在通过筛选器链。 (您正在阅读调试日志,对吗?)。

使用 URL 属性时,授权 JSP 标记不遵守我的方法安全 Comments。

当在<sec:authorize>中使用url属性时,方法安全性不会隐藏链接,因为我们无法轻易地反向工程哪些 URLMap 到哪个控制器端点,因为控制器可以依赖 Headers,当前用户等来确定要调用的方法。

15.5.3 Spring 安全架构问题

如何知道 X 属于哪个包类?

定位类的最佳方法是在 IDE 中安装 Spring Security 源代码。该发行版包括项目分成的每个模块的源 jar。将它们添加到项目源路径中,您可以直接导航到 Spring Security 类(在 Eclipse 中为Ctrl-Shift-T)。这也使调试更加容易,并允许您通过直接查看异常发生的地方来查看异常情况,从而对异常进行故障排除。

名称空间元素如何 Map 到常规 bean 配置?

在参考指南的名称空间附录中,概述了由名称空间创建的 bean。 blog.springsource.com上还有一篇详细的博客文章,名为“ Spring Security 命名空间的背后”。如果想知道全部细节,那么代码在 Spring Security 3.0 发行版的spring-security-config模块中。您可能应该先阅读标准 Spring Framework 参考文档中有关名称空间解析的章节。

“ ROLE_”是什么意思,为什么我在角色名称上需要它?

Spring Security 具有基于投票者的架构,这意味着访问决策由一系列AccessDecisionVoter s 决定。投票者根据为安全资源指定的“配置属性”(例如方法调用)进行操作。使用这种方法,并非所有属性都可能与所有选民都相关,因此选民需要知道何时应该忽略属性(弃权)以及何时应该投票基于属性值授予或拒绝访问权限。最常见的投票者是RoleVoter,默认情况下,只要找到具有“ ROLE_”前缀的属性,投票者就会投票。它将属性(例如“ ROLE_USER”)与当前用户已分配的权限名称进行简单比较。如果找到匹配项(它们具有称为“ ROLE_USER”的权限),则投票批准授予访问权限,否则投票拒绝访问。

可以通过设置RoleVoterrolePrefix属性来更改前缀。如果只需要在应用程序中使用角色,而无需其他自定义投票者,则可以将前缀设置为空白字符串,在这种情况下RoleVoter会将所有属性视为角色。

如何知道要添加到我的应用程序中的哪些依赖项才能使用 Spring Security?

这将取决于您使用的功能以及所开发的应用程序类型。使用 Spring Security 3.0,项目 jar 可以分为明显不同的功能区域,因此可以很容易地从应用程序需求中确定所需的 Spring Security jar。所有应用程序都需要spring-security-core jar。如果要开发 Web 应用程序,则需要spring-security-web jar。如果使用安全名称空间配置,则需要spring-security-config jar,要获得 LDAP 支持,则需要spring-security-ldap jar,依此类推。

对于第三方罐子,情况并不总是那么明显。一个好的起点是从一个预先构建的示例应用程序 WEB-INF/lib 目录中复制这些文件。对于基本应用程序,您可以从教程示例开始。如果要对嵌入式测试服务器使用 LDAP,请以 LDAP 示例为起点。参考手册还包括 http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#appendix-dependencies [附录]列出了每个 Spring 的第一级依赖关系安全模块,其中包含有关它们是否可选以及所需功能的一些信息。

如果您使用 Maven 构建项目,则将适当的 Spring Security 模块作为依赖项添加到 pom.xml 中,将自动提取框架所需的核心 jar。如果需要,任何在 Spring Security POM 文件中标记为“可选”的文件都必须添加到您自己的 pom.xml 文件中。

运行嵌入式 ApacheDS LDAP 服务器需要哪些依赖项?

如果使用的是 Maven,则需要将以下内容添加到 pom 依赖项中:

<dependency>
        <groupId>org.apache.directory.server</groupId>
        <artifactId>apacheds-core</artifactId>
        <version>1.5.5</version>
        <scope>runtime</scope>
</dependency>
<dependency>
        <groupId>org.apache.directory.server</groupId>
        <artifactId>apacheds-server-jndi</artifactId>
        <version>1.5.5</version>
        <scope>runtime</scope>
</dependency>

其他需要的罐子应暂时移入。

什么是 UserDetailsService,我需要一个吗?

UserDetailsService是 DAO 界面,用于加载特定于用户帐户的数据。除了加载该数据以供框架中的其他组件使用外,它没有其他功能。它不负责验证用户身份。使用用户名/密码组合对用户进行身份验证通常是由DaoAuthenticationProvider执行的,DaoAuthenticationProvider被注入UserDetailsService以便允许它为用户加载密码(和其他数据),以便将其与提交的值进行比较。请注意,如果您使用的是 LDAP,则为这种方法可能行不通

如果要自定义身份验证过程,则应自己实现AuthenticationProvider。有关将 Spring Security 身份验证与 Google App Engine 集成的示例,请参见此blog article

15.5.4 常见的“操作方法”请求

我需要登录的信息不仅仅是用户名。

如何添加对额外登录字段(例如公司名称)的支持?

这个问题在 Spring Security 论坛中反复出现,因此您可以通过搜索 Files(或通过 google)在那里找到更多信息。

提交的登录信息由UsernamePasswordAuthenticationFilter实例处理。您将需要自定义此类以处理额外的数据字段。一种选择是使用您自己的自定义身份验证令牌类(而不是标准的UsernamePasswordAuthenticationToken),另一种是简单地将多余的字段与用户名连接起来(例如,使用“:”作为分隔符),并将其传递给 username 属性的UsernamePasswordAuthenticationToken

您还需要自定义实际的身份验证过程。例如,如果使用的是自定义身份验证令牌类,则必须编写一个AuthenticationProvider来处理它(或扩展标准DaoAuthenticationProvider)。如果您串联了这些字段,则可以实现自己的UserDetailsService,将其拆分并加载适当的用户数据以进行身份验证。

如何仅在所请求的 URL 的片段值不同的情况下应用不同的拦截 URL 约束(例如,/ foo#bar 和/ foo#blah?

您无法执行此操作,因为该片段不会从浏览器传输到服务器。从服务器的角度来看,上面的 URL 是相同的。这是 GWT 用户的常见问题。

如何在 UserDetailsService 中访问用户的 IP 地址(或其他 Web 请求数据)?

显然,您不能(不求助于线程局部变量),因为提供给接口的唯一信息是用户名。代替实现UserDetailsService,您应直接实现AuthenticationProvider并从提供的Authentication令牌中提取信息。

在标准的 Web 设置中,Authentication对象上的getDetails()方法将返回WebAuthenticationDetails的实例。如果需要其他信息,可以将自定义AuthenticationDetailsSource注入正在使用的身份验证过滤器中。如果使用命名空间(例如,使用<form-login>元素),则应删除该元素,并用指向明确配置的UsernamePasswordAuthenticationFilter<custom-filter>声明替换它。

如何从 UserDetailsService 访问 HttpSession?

您不能这样做,因为UserDetailsService不了解 Servlet API。如果要存储自定义用户数据,则应自定义返回的UserDetails对象。然后可以通过本地线程SecurityContextHolder随时访问它。调用SecurityContextHolder.getContext().getAuthentication().getPrincipal()将返回此自定义对象。

如果您确实需要访问该会话,则必须通过自定义 Web 层来完成。

如何在 UserDetailsService 中访问用户密码?

您不能(也不应该)。您可能会误解其目的。请参阅上方的“ 什么是 UserDetailsService?”。

如何动态定义应用程序中的安全 URL?

人们经常问如何在数据库中而不是在应用程序上下文中存储安全 URL 和安全元数据属性之间的 Map。

您应该问自己的第一件事是您是否真的需要这样做。如果应用程序需要安全保护,则还需要根据定义的策略对安全性进行彻底测试。在将其推广到生产环境之前,可能需要进行审核和验收测试。一个安全意识强的组织应该意识到,通过更改配置数据库中的一两行,可以在运行时修改安全设置,可以立即消除其辛苦的测试过程的好处。如果考虑到这一点(可能在应用程序中使用多层安全性),那么 Spring Security 允许您完全自定义安全性元数据的来源。如果选择,可以使其完全动态。

方法和 Web 安全都受到AbstractSecurityInterceptor子类的保护,该子类配置了SecurityMetadataSource,从子类中可以获取特定方法或过滤器调用的元数据。为了网络安全,拦截器类为FilterSecurityInterceptor,并且使用标记接口FilterInvocationSecurityMetadataSource。它操作的“受保护对象”类型是FilterInvocation。使用的默认实现(在名称空间<http>中,并且在显式配置拦截器时)都将 URL 模式列表及其对应的“配置属性”列表(ConfigAttribute的实例)存储在内存 Map 中。

要从备用源加载数据,必须使用显式声明的安全过滤器链(通常是 Spring Security 的FilterChainProxy)来定制FilterSecurityInterceptor bean。您不能使用名称空间。然后,您可以实现FilterInvocationSecurityMetadataSource以根据需要为特定的FilterInvocation [25]加载数据。一个非常基本的轮廓如下所示:

public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    public List<ConfigAttribute> getAttributes(Object object) {
        FilterInvocation fi = (FilterInvocation) object;
            String url = fi.getRequestUrl();
            String httpMethod = fi.getRequest().getMethod();
            List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();

            // Lookup your database (or other source) using this information and populate the
            // list of attributes

            return attributes;
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

有关更多信息,请查看DefaultFilterInvocationSecurityMetadataSource的代码。

如何针对 LDAP 进行身份验证,但如何从数据库中加载用户角色?

LdapAuthenticationProvider bean(在 Spring Security 中处理普通的 LDAP 身份验证)配置有两个单独的策略接口,一个用于执行身份验证,另一个用于加载用户权限,分别称为LdapAuthenticatorLdapAuthoritiesPopulatorDefaultLdapAuthoritiesPopulator从 LDAP 目录中加载用户权限,并具有各种配置参数,以允许您指定应如何检索这些权限。

要改为使用 JDBC,您可以使用适合您的模式的任何 SQL 自己实现接口:

public class MyAuthoritiesPopulator implements LdapAuthoritiesPopulator {
    @Autowired
    JdbcTemplate template;

    List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
        List<GrantedAuthority> = template.query("select role from roles where username = ?",
                                                                                                new String[] {username},
                                                                                                new RowMapper<GrantedAuthority>() {
            /**
             *  We're assuming here that you're using the standard convention of using the role
             *  prefix "ROLE_" to mark attributes which are supported by Spring Security's RoleVoter.
             */
            public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                return new SimpleGrantedAuthority("ROLE_" + rs.getString(1);
            }
        }
    }
}

然后,您可以将这种类型的 bean 添加到您的应用程序上下文中,并将其注入LdapAuthenticationProvider。在参考手册的 LDAP 章节中有关使用显式 Spring Bean 配置 LDAP 的部分中对此进行了介绍。请注意,在这种情况下,不能使用名称空间进行配置。您还应该向 Javadoc 查询相关的类和接口。

我想修改由名称空间创建的 bean 的属性,但是架构中没有任何东西可以支持它。

除了放弃命名空间使用外,我还能做什么?

命名空间功能是有意限制的,因此不能涵盖使用普通 bean 可以做的所有事情。如果您想做一些简单的事情,例如修改 bean 或注入不同的依赖项,则可以通过在配置中添加BeanPostProcessor来实现。可以在Spring 参考手册中找到更多信息。为此,您需要对创建哪些 bean 有一点了解,因此,您还应该阅读有关命名空间如何 Map 到 Spring Bean的上述问题中的博客文章。

通常,您需要将所需的功能添加到BeanPostProcessorpostProcessBeforeInitialization方法中。假设您要自定义UsernamePasswordAuthenticationFilter使用的AuthenticationDetailsSource(由form-login元素创建)。您想要从请求中提取名为CUSTOM_HEADER的特定 Headers,并在验证用户身份时使用它。处理器类如下所示:

public class BeanPostProcessor implements BeanPostProcessor {

        public Object postProcessAfterInitialization(Object bean, String name) {
                if (bean instanceof UsernamePasswordAuthenticationFilter) {
                        System.out.println("********* Post-processing " + name);
                        ((UsernamePasswordAuthenticationFilter)bean).setAuthenticationDetailsSource(
                                        new AuthenticationDetailsSource() {
                                                public Object buildDetails(Object context) {
                                                        return ((HttpServletRequest)context).getHeader("CUSTOM_HEADER");
                                                }
                                        });
                }
                return bean;
        }

        public Object postProcessBeforeInitialization(Object bean, String name) {
                return bean;
        }
}

然后,您将在应用程序上下文中注册此 bean。 Spring 将在应用程序上下文中定义的 bean 上自动调用它。


[22]有关如何从web.xml设置 Map 的信息,请参见introductory chapter

[23]实际上,此功能只是为了方便起见而提供的,并非供生产使用(已选择一种查看技术,可用于呈现自定义的登录页面)。 DefaultLoginPageGeneratingFilter类负责呈现登录页面,并将在需要时为普通表单登录和/或 OpenID 提供登录表单。

[24]这不会影响PersistentTokenBasedRememberMeServices的使用,令牌存储在服务器端。

[25] FilterInvocation对象包含HttpServletRequest,因此您可以获取 URL 或任何其他相关信息,并根据这些信息来确定返回的属性列表将包含哪些内容。