前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >打造更RESTful的身份认证【Spring Security】

打造更RESTful的身份认证【Spring Security】

作者头像
烟雨平生
发布2023-03-07 14:51:28
6390
发布2023-03-07 14:51:28
举报
文章被收录于专栏:数字化之路数字化之路
清泉石上流 from zhangjunfeng

原文链接:https://www.baeldung.com/spring-nosuchbeandefinitionexception

作者:Eugen Paraschiv

译者:helloworldtang

目录

  • 1.概览
  • 2.配置 Basic身份认证
  • 2.1.满足无状态约束 –弃用 Session
  • 3.配置 Digest身份认证
  • 4. 在同一个RESTful服务中同时支持两种认证协议
  • 4.1. 匿名请求
  • 4.2.携带身份认证凭据的请求
  • 5. 测试这两个场景
  • 6. 总结

1. 概览

本文讨论了如何在REST API的相同URI结构上同时配置 BasicDigest身份认证。在前一篇文章中,我们讨论了保护REST服务的另一种场景——基于表单的身份认证,因此 BasicDigest身份认证成了自然而然的选择,其实,这也是更RESTful的身份认证。

2. 配置 Basic身份认证

对于RESTful服务来说,基于表单的身份认证并不理想的主要原因是,Spring Security会使用 Session——这当然是指存放在服务器上的状态,因此REST中的无状态约束实际上并没有实现。

我们将从建立 Basic身份认证开始——首先,我们删除旧的自定义 认证入口配置开始:

代码语言:javascript
复制
<http create-session="stateless">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

   <http-basic />
</http>

请注意, Basic身份认证的特性是通过一行配置<http-basic />来完成的,这行配置完成了BasicAuthenticationFilter和BasicAuthenticationEntryPoint的创建和织入。

2.1.满足无状态约束 –弃用 Session

RESTful架构风格的主要限制之一,客户端-服务器通信需要是完全无状态的,正如原始论文中所描述的那么。

5.1.3 无状态 接下来,我们需要向客户端-服务器交互添加一个约束:通信在本质上必须是无状态的,就像在第3.4.3节(图5-3)的客户端-无状态的服务器(CSS)一样,这样客户端到服务器的每个请求都必须包含识别请求所需的所有信息,并且不能利用存储在服务器上下文中的任何身份信息。 因此会话状态是完全保存在客户端的。

在Spring Security中,服务器 Session的概念具有悠久的历史,但是直到现在才能够完全废弃掉,特别是通过 命名空间来完成相关配置时。

然而,对于会话创建,Spring Security通过使用一个新的 stateless选项来扩展 命名空间配置参数,这就能有效地保证了Spring不会创建或使用任何会话。这个新选项所做的就是从安全过滤器链中删除所有与会话相关的过滤器,确保对每个请求都执行身份认证。

3. 配置 Digest身份认证

从前面的配置开始, Digest身份验证所需的过滤器和认证入口点都将被定义为 Bean。然后, Digest认证入口点将覆盖由<http-basic />创建的默认过滤器。最后,将在安全过滤器链中引自定义的 Digest过滤器,使用命名空间的after语义指定其在 Basic身份认证过滤器之后生效。

代码语言:javascript
复制
<http create-session="stateless" entry-point-ref="digestEntryPoint">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

   <http-basic />
   <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>

<beans:bean id="digestFilter" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
   <beans:property name="userDetailsService" ref="userService" />
   <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" />
</beans:bean>

<beans:bean id="digestEntryPoint" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
   <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/>
   <beans:property name="key" value="acegi" />
</beans:bean>

<authentication-manager>
   <authentication-provider>
      <user-service id="userService">
         <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" />
         <user name="user" password="user" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>

不幸的是,在security命名空间中并不支持自动配置 Digest身份认证,而 Basic身份认证可以使用配置<http-basic />来完成。因此,要配置 Digest身份认证,必须手动添加必要的 Bean定义并手动连接到安全配置中。

4. 在同一个RESTful服务中同时支持两种认证协议

仅在Spring Security中就可以容易地实现 BasicDigest身份认证;它为相同的RESTful Web服务和在相同的URI映射上都提供了支持,这给服务的配置和测试引入了新的复杂度。

4.1. 匿名请求

在安全链中有 BasicDigest身份认证过滤器,一个匿名请求——一个包含没有身份认证凭证(Authorization HTTP头)的请求——是由Spring Security处理的——这两个身份验证过滤器将发现没有身份凭证,并将继续执行过滤器链。 然后,看到请求没有通过身份认证,就会抛出AccessDeniedException异常,并捕获到ExceptionTranslationFilter中,该过滤器将引入 Digest认证入口点,并提示客户端需要凭证。

BasicDigest过滤器的职责都是很具体的——如果无法识别请求中的身份认证凭证的类型,则它们将继续执行安全过滤器链。正因为如此,Spring Security在同一URI支持多种认证协议方面,具有很好的灵活性。

当发出包含正确身份认证凭据( BasicDigest)的请求时,该协议将被正确使用。但是,对于匿名请求,客户端只会收到需要 Digest认证凭据的提示。这是因为 Digest入口点被配置为Spring安全链的主要入口点,并且是单一入口点;这样的 Digest身份认证可以被认为是默认的

4.2. 携带认证凭据的请求

带有 Basic身份认证凭据的请求将由以“ Basic”开头的Authorization HTTP头标识。当处理这样的请求时,凭证将在 Basic身份认证过滤器中被解码,并且请求将被授权。类似地,具有 Digest身份认证凭证的请求将使用前缀为“Digest”的Authorization HTTP头。

5. 测试这两个场景

这个测试用例将在 BasicDigest身份认证后,通过创建一个新资源来消费REST服务:

代码语言:javascript
复制
@Test
public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( paths.getFooURL() );

   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}
@Test
public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( paths.getFooURL() );

   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}

注意,这个使用 Basic身份认证的测试会预先向请求添加凭证,而不管服务器是否需要身份认证。这是为了确保服务器不需要向客户端询问凭据,因为如果是这样,则询问将是针对默认的 Digest凭据。

6. 总结

本文讨论了RESTful服务中 BasicDigest身份认证的配置及实现,主要使用Spring Security 命名空间以及框架中的一些新特性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 1. 概览
  • 2. 配置 Basic身份认证
    • 2.1.满足无状态约束 –弃用 Session
    • 3. 配置 Digest身份认证
    • 4. 在同一个RESTful服务中同时支持两种认证协议
      • 4.1. 匿名请求
        • 4.2. 携带认证凭据的请求
        • 5. 测试这两个场景
        • 6. 总结
        相关产品与服务
        多因子身份认证
        多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档