5. Java Configuration Java配置

在Spring 3.1中,对 Java Configuration (Java配置)的一般支持被添加到Spring框架中。自Spring Security 3.2以来,就有了Spring Security对Java配置的支持,用户可以轻松配置Spring Security,而无需使用任何XML。

如果您熟悉第6章“安全命名空间配置”,那么您应该会发现它和安全Java配置支持之间有很多相似之处。

Spring Security提供了 lots of sample applications (许多示例应用程序),演示了Spring Security Java配置的使用。

5.1  Web Security Java Configuration(网络安全Java配置)

第一步是创建我们的Spring安全Java配置。该配置创建了一个名为springSecurityFilterChain的Servlet过滤器,它负责应用程序中的所有安全性(保护应用程序URL、验证提交的用户名和密码、重定向到登录表单等)。您可以在下面找到Spring安全Java配置的最基本的例子:


 

1、这里真没有配置多少内容,但它确实很有用。您可以找到以下功能的摘要:

2、在你的应用程序中对每个URL进行验证

3、为你生成一个登陆表单

4、允许使用用户名Usernameuser和密码Passwordpassword使用验证表单进行验证。

5、允许用户登出

6、CSRF attackCSPF攻击防范

7、Session FixationSession保护

8、安全 Header 集成

 HTTP Strict Transport Security对安全要求严格的HTTP传输安全

 X-Content-Type-OptionsX-Content-Type-Options集成

        缓存控制(稍后可以允许你缓存静态资源)

 X-XSS-ProtectionX-XSS-Protection集成

X-Frame-Options 集成防止点击劫持Clickjacking

9、和以下 Servlet API 方法集成

HttpServletRequest#getRemoteUser()

 HttpServletRequest.html#getUserPrincipal()

 HttpServletRequest.html#isUserInRole(java.lang.String)

 HttpServletRequest.html#login(java.lang.String, java.lang.String)

 HttpServletRequest.html#logout()

5.1.1 AbstractSecurityWebApplicationInitializer(抽象安全网络应用程序初始化器)

下一步是将springSecurityFilterChain注册到war中。这可以在Servlet 3.0+环境中通过支持Spring的WebApplicationInitializer在Java配置中完成。不足为奇的是,Spring Security提供了一个基类AbstractSecurityWebApplicationInitializer(抽象安全性应用程序初始化器),它将确保为您注册springSecurityFilterChain。我们使用AbstractSecurityWebApplicationInitializer(抽象安全性应用程序初始化器)的方式会有所不同,这取决于我们是否已经在使用Spring,或者Spring安全性是我们的应用程序中唯一的Spring组件。

第5.1.2节,“AbstractSecurityWebApplicationInitializer without Existing Spring”-如果您还没有使用Spring,请使用这些说明。

第5.1.3节,“AbstractSecurityWebApplicationInitializer with Spring MVC”-如果您已经在使用Spring,请使用这些说明。

5.1.2 AbstractSecurityWebApplicationInitializer without Existing Spring(没有现有Spring的抽象安全性应用程序初始化器)

如果您没有使用Spring或Spring MVC,您将需要将网络安全参数(WebSecurityConfig)传入超类,以确保配置被采用。你可以在下面找到一个例子:


 

安全性应用程序初始化器(SecurityWebApplicationInitializer)将执行以下操作:

为应用程序中的每个网址自动注册到springSecurityFilterChain过滤器。

添加一个加载网络安全配置(WebSecurityConfig)的上下文加载器(ContextLoaderListener)。

5.1.3 AbstractSecurityWebApplicationInitializer with Spring MVC(有springMVC的抽象安全性应用程序初始化器 )

如果我们在应用程序的其他地方使用Spring,我们可能已经有了一个加载Spring配置的WebApplicationInitializer(web应用初始化器)。如果我们使用以前的配置,我们会得到一个错误。相反,我们应该在现有的应用上下文(ApplicationContext)中注册Spring Security。例如,如果我们使用的是Spring MVC,我们的SecurityWebApplicationInitializer(安全web应用初始化器)看起来就像下面这样:


 

这只会为应用程序中的每个网址注册springSecurityFilterChain过滤器。之后,我们将确保WebSecurityConfig(web安全配置)加载到我们现有的应用程序初始化器中。例如,如果我们使用Spring MVC,它将被添加到getRootConfigClasses():


5.2 HttpSecurity(http安全)

到目前为止,我们的网络安全配置只包含如何验证用户身份的信息。Spring Security如何知道我们想要要求所有用户都经过身份验证?Spring Security如何知道我们想要支持基于表单的身份验证?原因是WebSecurityConfigurerAdapter(web安全配置适配器)在configure(HttpseSecurity http)方法中提供了一个默认配置,如下所示:


 

上面的默认配置:

确保我们应用中的所有请求都需要用户被认证

允许用户进行基于表单的认证

允许用户使用HTTP基于验证进行认证

你可以看到这个配置和下面的XML命名配置相似:


 

java配置使用and()方法相当于XML标签的关闭。这允许我们继续配置父对象。如果你阅读代码,它也是有意义的。我想配置授权请求,配置表单登录和配置HTTP基本身份验证。

然而,Java配置有不同的默认URL和参数。创建自定义登录页面时请记住这一点。结果是,我们的网址更加RESTful。此外,我们使用有助于防止信息泄露的Spring Security并不十分明显。例如5.3所示:

5.3 Java Configuration and Form Login(java配置和表单登录)

当提示您登录时,您可能想知道登录表单是从哪里来的,因为我们没有提到任何HTML文件或JSP。由于Spring Security的默认配置没有为登录页面明确设置URL,Spring Security会根据已启用的功能自动生成一个,并使用处理提交的登录的URL的标准值、用户登录后将被发送到的默认目标URL等等。

虽然自动生成的登录页面便于快速启动和运行,但大多数应用程序都希望提供自己的登录页面。为此,我们可以更新我们的配置,如下所示:


 

1、指定登录页的路径

2、我们必须允许所有用户访问我们的登录页(例如为验证的用户),这个formLogin().permitAll()方法允许基于表单登录的所有的URL的所有用户的访问。

下面是我们当前配置的一个用JSPs实现的登录页面示例:

下面的登录页面代表我们当前的配置。如果某些默认值不能满足我们的需求,我们可以轻松地更新我们的配置。


 

1、一个POST请求到/login用来验证用户

2、如果参数有error, 验证尝试失败

3、如果请求蚕食logout存在则登出

4、登录名参数必须被命名为username

5、密码参数必须被命名为password

6、我们必须阅读第18.4.3节“包含CSRF令牌”(Section 18.4.3, “Include the CSRF Token”)以了解更多信息,请阅读第18章“跨站点请求伪造(CSRF)”(Chapter 18,Cross Site Request Forgery (CSRF))一节的参考资料

5.4 Authorize Requests(请求授权)

我们的例子中要求用户进行身份验证并且在我们应用程序的每个URL这样做。我么你可以通过给http.authorizeRequests()添加多个子节点来指定多个定制需求到我们的URL。例如:


 

1、http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺序执行。

2、我们指定任何用户都可以通过访问的多个URL模式。任何用户都可以访问URL以"/resources/", equals "/signup", 或者 "/about"开头的URL。

3、以 "/admin/" 开头的URL只能由拥有 "ROLE_ADMIN"角色的用户访问。请注意我们使用 hasRole 方法,没有使用 "ROLE_" 前缀。

4、任何以"/db/" 开头的URL需要用户同时具有 "ROLE_ADMIN" 和 "ROLE_DBA"。和上面一样我们的 hasRole 方法也没有使用 "ROLE_" 前缀。

5、尚未匹配的任何URL要求用户进行身份验证。

5.5 Handling Logouts(登出处理)

当使用WebSecurityConfigurerAdapter, 注销功能会自动应用。默认是访问URL`/logout`将注销登陆的用户:

使HTTP Session 无效

清楚所有已经配置的 RememberMe 认证

清除SecurityContextHolder

重定向到 /login?logout


 

1、提供注销支持,使用WebSecurityConfigurerAdapter会自动被应用。

2、设置触发注销操作的URL (默认是/logout). 如果CSRF内启用(默认是启用的)的话这个请求的方式被限定为POST。 请查阅相关信息JavaDoc相关信息.

3、注销之后跳转的URL。默认是/login?logout。具体查看JavaDoc文档.

4、让你设置定制的 LogoutSuccessHandler。如果指定了这个选项那么logoutSuccessUrl()的设置会被忽略。请查阅JavaDoc文档.

5、指定是否在注销时让HttpSession无效。 默认设置为true。 在内部配置SecurityContextLogoutHandler,有关更多信息, 请查阅JavaDoc文档.

6、添加一个LogoutHandler,默认情况下SecurityContextLogoutHandler会被添加为最后一个LogoutHandler。

7、允许指定在注销成功时将移除的cookie。这是一个显示的添加一个CookieClearingLogoutHandler的快捷方式。

注销也可以通过XML命名空间进行配置,请参阅Spring Security XML命名空间相关文档获取更多细节logout element

5.5.1 LogoutHandler(登出处理器)

通常,LogoutHandle的r实现类能够参与到注销处理中。它们将被调用来执行必要的清理。因此,他们不应该抛出异常。提供了各种实现方式:

PersistentTokenBasedRememberMeServices(基于持久令牌的记忆服务)

TokenBasedRememberMeServices(基于令牌的记忆服务)

CookieClearingLogoutHandler(Cookie清除注销处理程序)

CsrfLogoutHandler(Csrf注销处理程序)

SecurityContextLogoutHandler(安全上下文注销处理程序)

详情请参见第17.4节“记住我的界面和实现”。(Section 17.4, “Remember-Me Interfaces and Implementations”

除了直接提供LogoutHandler实现,fluent应用编程接口还提供了快捷方式,这些快捷方式在封面下提供了各自的LogoutHandler实现。例如,deleteCookies()允许指定注销成功时要删除的一个或多个cookies的名称。与添加CookieClearingLogoutHandler相比,这是一个快捷方式。

5.5.2 LogoutSuccessHandler(登出成功处理器)

LogoutSuccessHandler(登出成功处理器)被LogoutFilter(登出处理器)在成功注销后调用,用来进行重定向或者转发相应的目的地。注意这个接口与LogoutHandler(登出处理器)几乎一样,但是可以抛出异常。

下面是提供的一些实现:

SimpleUrlLogoutSuccessHandler(简单URL登出成功处理器)

HttpStatusReturningLogoutSuccessHandler(http状态返回登出成功处理器)

和前面提到的一样,你不需要直接指定SimpleUrlLogoutSuccessHandler(简单URL登出成功处理器)。而使用流式API接口通过设置logoutSuccessUrl(登出成功URL)快捷方式进行设置SimpleUrlLogoutSuccessHandler简单URL登出成功处理器)。注销成功 后将重定向到设置的URL地址。默认的地址是 /login?logout。

在REST API场景中HttpStatusReturningLogoutSuccessHandlerhttp状态返回登出成功处理器)会进行一些有趣的改变。LogoutSuccessHandler(登出成功处理器)允许你设置一个返回给客户端的HTTP状态码(默认返回200)来替换重定向到URL这个动作。

5.5.3 Further Logout-Related References(进一步登出相关参考)

Logout Handling(登出处理)

Testing Logout(登出测试)

HttpServletRequest.logout()(HTTPServletRequest登出)

Section 17.4, “Remember-Me Interfaces and Implementations”(Remember-Me接口和实现)

Logging Outin section CSRF Caveats (登出CSRF说明)

SectionSingle Logout(CAS protocol)(单点登出)

Documentation for thelogout elementin the Spring Security XML Namespace section(Spring安全XML命名空间部分中注销元素的文档)

5.6 Authentication(认证)

到目前为止,我们只看了最基本的身份验证配置。让我们看几个稍微高级一点的配置身份验证的选项。

5.6.1 In-Memory Authentication(内存中的身份验证)

我们已经看到了一个单用户配置到内存验证的示例,下面是配置多个用户的例子:

 


 

5.6.2 JDBC Authentication(jdbc认证)

你可以找一些更新来支持JDBC的验证。下面的例子假设你已经在应用程序中定义好了DataSource, jdbc-javaconfig 示例提供了一个完整的基于JDBC的验证。

 


 

5.6.3 LDAP Authentication(LDAP认证)

你可以找一些更新来支持LDAP的身份验证, ldap-javaconfig 提供了一个完成的使用基于LDAP的身份验证的示例。

 


 

上面的例子使用了下面的LDIF和一个嵌入的Apache DS LDAP实例。

dn: ou=groups,dc=springframework,dc=org

objectclass: top

objectclass: organizationalUnit

ou: groups

dn: ou=people,dc=springframework,dc=org

objectclass: top

objectclass: organizationalUnit

ou: people

dn: uid=admin,ou=people,dc=springframework,dc=org

objectclass: top

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

cn: Rod Johnson

sn: Johnson

uid: admin

userPassword: password

dn: uid=user,ou=people,dc=springframework,dc=org

objectclass: top

objectclass: person

objectclass: organizationalPerson

objectclass: inetOrgPerson

cn: Dianne Emu

sn: Emu

uid: user

userPassword: password

dn: cn=user,ou=groups,dc=springframework,dc=org

objectclass: top

objectclass: groupOfNames

cn: user

uniqueMember: uid=admin,ou=people,dc=springframework,dc=org

uniqueMember: uid=user,ou=people,dc=springframework,dc=org

dn: cn=admin,ou=groups,dc=springframework,dc=org

objectclass: top

objectclass: groupOfNames

cn: admin

uniqueMember: uid=admin,ou=people,dc=springframework,dc=org

5.6.4 AuthenticationProvider(认证提供商)

您可以通过一个自定义的AuthenticationProvider为bean定义自定义身份验证。 例如, 下面这个例子假设自定义身份验证SpringAuthenticationProvider实现了AuthenticationProvider:

仅当尚未填充AuthenticationManagerBuilder时,才使用此选项。

 


 

5.6.5 UserDetailsService(用户详细信息服务)

你可以通过一个自定义的UserDetailsService(用户详细信息服务)为bean定义自定义身份验证。 例如,下面这个例子假设自定义身份验证SpringDataUserDetailsService实现了UserDetailsService:

仅当尚未填充AuthenticationManagerBuilder(身份验证管理器生成器)并且未定义AuthenticationProviderBean(身份验证提供商)时,才使用此选项。

 


 

你也可以通过让passwordencoder为bean自定义密码如何编码。 例如,如果你使用BCrypt,你可以添加一个bean定义如下图所示:

 


5.6.6 LDAP Authentication(LDAP身份认证)

5.7 Multiple HttpSecurity(多个HttpSecurity)

我们可以配置多个http安全实例,就像我们可以有多个< http >块一样。关键是多次扩展WebSecurityConfigurerAdapter。例如,下面是一个为以/api/开头的网址进行不同配置的示例。

 


 

配置正常的验证。

1、创建一个WebSecurityConfigurerAdapter,包含一个@Order注解,用来指定个哪一个WebSecurityConfigurerAdapter更优先。

2、http.antMatcher指出,这个HttpSecurity只应用到以/api/开头的URL上。

3、创建另外一个WebSecurityConfigurerAdapter实例。用于不以/api/开头的URL,这个配置的顺序在ApiWebSecurityConfigurationAdapter之后,因为他没有指定@Order值为1(没有指定@Order默认会被放到最后).

5.8 Method Security(方法安全性)

从版本2.0开始,Spring Security已经大大改进了对为服务层方法增加安全性的支持。它支持JSR-250注释安全性以及框架的原始@Secured注释。从3.0开始,您还可以使用新的基于表达式(expression-based annotations.)的注释。您可以对单个bean应用安全性,使用intercept-methods元素来修饰bean声明,或者使用AspectJ风格的切入点来保护整个服务层中的多个bean。

5.8.1 EnableGlobalMethodSecurity(启用全局方法安全性)

我们可以在任何@Configuration实例上使用@EnableGlobalMethodSecurity注释来启用基于注释的安全性。例如,下面将启用Spring Security的@Secured注释。

 


 

向方法(在类或接口上)添加注释会相应地限制对该方法的访问。Spring Security的原生注释支持为该方法定义了一组属性。这些将被传递给AccessDecisionManager(访问决策管理器),以便它做出实际的决策:

 


 

使用如下代码启用JSR-250注解的支持

 


 

这些都是基于标准的,允许应用简单的基于角色的约束,但不具备Spring Security的原生注释。要使用新的基于表达式的语法,您应该使用

 


 

等效的Java代码是

 


 

5.8.2 GlobalMethodSecurityConfiguration(全局方法安全性配置)

有时您可能需要执行比@EnableGlobalMethodSecurity注释允许的操作更复杂的操作。对于这些实例,您可以扩展GlobalMethodsecurityConfiguration(全局方法安全性配置),确保您的子类中存在@EnableGlobalMethodSecurity注释。例如,如果您想提供一个自定义的MethodSecurityExpressionHandler(方法安全表达式处理程序),您可以使用以下配置:

 


 

关于可以被重写的方法的更多信息,请参考GlobalMethodSecurityConfiguration(全局方法安全性配置)的java文档。

5.9 Post Processing Configured Objects(后置处理配置的对象)

Spring Security的Java配置没有公开它配置的每个对象的每个属性。这简化了大多数用户的配置。毕竟,如果每个属性都公开了,用户可以使用标准的bean配置。

虽然有充分的理由不直接公开每个属性,但是用户可能仍然需要更高级的配置选项。为了解决这个问题,Spring Security引入了ObjectPostProcessor(后置对象处理器)的概念,它可以用来修改或替换许多由Java配置创建的对象实例。例如,如果您想在FilterSecurityInterceptor(安全过滤拦截器)上配置FilterSecurityPublishauthorizationSuccess(安全过滤发布授权成功)属性,可以使用以下方法:

 


 

5.10 Custom DSLs(自定义DSLs)

您可以在Spring Security中提供自己的定制DSL。例如,你可能有这样的东西:

 


 

这实际上是像HttpSecurity.authorizeRequests()这样的方法是来实现的。

自定义DSL可以这样使用:

 


 

代码按以下顺序调用:

1、调用“配置”的配置方法中的代码

2、调用了“MyCustomDsl的初始化方法”中的代码

3、调用了“MyCustomDsl的配置方法”中的代码

如果需要,您可以使用SpringFactories让WebSecurityConfiguerAdapter默认添加MyCustomDsl。例如,您可以在类路径上创建一个名为META-INF/spring.factories的资源,其内容如下:

org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyCustomDsl

希望禁用默认值的用户可以明确地这样做。

 


 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-08-16 16:34  节日快乐  阅读(1033)  评论(0编辑  收藏  举报