`
lengyun3566
  • 浏览: 453758 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
D59180b9-02f1-3380-840c-ea34da46143c
《Spring Secur...
浏览量:384295
社区版块
存档分类
最新评论

《Spring Security3》第六章第二部分翻译(自定义AuthenticationProvider)

阅读更多

 

实现自定义的AuthenticationProvider

在很多场景下,你的应用需要跳出Spring Security功能的边界,可能会需要实现自己的AuthenticationProvider。回忆在第二章中AuthenticationProvider的角色,在整个认证过程中,它接受安全实体请求提供的凭证(即Authentication对象或authentication token)并校验其正确性和合法性。

通过AuthenticationProvider实现一个简单的单点登录

通常,应用允许以用户或客户端方式登录。但是,有一种场景也很常见,尤其是在广泛使用的应用中,即允许系统中的不同用户以多种方式登录。

假设我们的系统与一个简单的“单点登录”提供者进行集成,用户名和密码分别在HTTP头中的j_username j_password发送。除此以外,j_signature头信息包含了用户名和密码的随意编码算法形成的字符串,以辅助安全请求。

【不要使用这个例子作为真实单点登录的解决方案。这个例子很牵强,只是为了说明实现一个完全自定义AuthenticationProvider的步骤。真正的SSO解决方案显然会更安全并涉及到几次的握手以建立可信任的凭证。Spring Security支持几种SSO解决方案,包括中心认证服务(CAS)和SiteMinder,我们将会在第十章:使用中心认证服务实现单点登录中介绍。实际上,Spring Security提供了一个类似的过滤器用来进行SiteMinder请求头的认证,即o.s.s.web.authentication.preauth.RequestHeaderAuthenticationFilter,也是这种类型功能的一个好例子。】

对于admin用户的登录,我们的算法期望在请求头中包含如下的数据:

请求头

j_username

admin

j_password

admin

j_signature

admin|+|admin

一般来讲,AuthenticationProvider将会寻找特定的AuthenticationToken,而后者会在过滤器链中位置比较靠前的servlet filter里面进行填充赋值(明确会在AuthenticationManager访问检查执行之前),如下图描述:


 

在这种方式中,AuthenticationToken的提供者与其消费者AuthenticationProvider有一点脱离关系了。所以,在实现自定义AuthenticationProvider时,通常还需要实现一个自定义的servlet过滤器,其作用是提供特定的AuthenticationToken

自定义认证token

我们实现自定义的方法会尽可能的使用Spring Security的基本功能。基于此,我们会扩展并增强基本类如UsernamePasswordAuthenticationToken,并添加一个新的域来存储我们已编码的签名字符串。最终的类com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationToken,如下:

 

package com.packtpub.springsecurity.security;
// imports omitted
  public class SignedUsernamePasswordAuthenticationToken 
extends UsernamePasswordAuthenticationToken {
    private String requestSignature;
    private static final long serialVersionUID = 
    3145548673810647886L;
  /**
   * Construct a new token instance with the given principal, 
credentials, and signature.
  * 
  * @param principal the principal to use
  * @param credentials the credentials to use
  * @param signature the signature to use
  */
  public SignedUsernamePasswordAuthenticationToken(String principal,
    String credentials, String signature) {
    super(principal, credentials);
    this.requestSignature = signature;
    }
  public void setRequestSignature(String requestSignature) {
    this.requestSignature = requestSignature;
    }
  public String getRequestSignature() {
    return requestSignature;
    }
} 

         我们可以看到SignedUsernamePasswordAuthenticationToken是一个简单的POJO类,扩展自UsernamePasswordAuthenticationTokenTokens并不需要太复杂——它们的主要目的就是为后面的校验封装凭证信息。

实现对请求头处理的servlet过滤器

         现在,我们要写servlet过滤器的代码,它负责将请求头转换成我们新定义的token。同样的,我们扩展对应的Spring Security基本类。在本例中,o.s.s.web.authentication.

AbstractAuthenticationProcessingFilter满足我们的要求。

【基本过滤器AbstractAuthenticationProcessingFilterSpring Security中是很多进行认证过滤器的父类(包括OpenID、中心认证服务以及基于form的用户名和密码登录)。这个类提供了标准的认证逻辑并适当织入了其它重要的资源如RememberMeServicesApplicationEventPublisher(本章的后面将会讲解到)。】

         现在,让我们看一下代码:

 

// imports omitted
  public class RequestHeaderProcessingFilter extends 
    AbstractAuthenticationProcessingFilter {
  private String usernameHeader = "j_username";
  private String passwordHeader = "j_password";
  private String signatureHeader = "j_signature";
  protected RequestHeaderProcessingFilter() {
    super("/j_spring_security_filter");
    }
  @Override
  public Authentication attemptAuthentication 
    (HttpServletRequest request,HttpServletResponse response) 
    throws AuthenticationException,
      IOException, ServletException {
    String username = request.getHeader(usernameHeader);
    String password = request.getHeader(passwordHeader);
    String signature = request.getHeader(signatureHeader);
    SignedUsernamePasswordAuthenticationToken authRequest = 
      new SignedUsernamePasswordAuthenticationToken 
      (username, password, signature);
    return this.getAuthenticationManager().authenticate(authRequest);
    }
  // getters and setters omitted below
} 

           可以看到,这个比较简单的过滤器查找三个已命名的请求头,正如我们已经规划的那样(如果需要的话,可以通过bean属性进行配置),并监听默认的URL  /j_spring_security_filter。正如其它的Spring Security过滤器那样,这是一个虚拟的URL并被我们的过滤器的基类AbstractAuthenticationProcessingFilter所识别,基于此这个过滤器采取行动尝试创建Authentication token并认证用户的请求。

【区分参与认证token流程的各个组件。在这个功能中,很容易被这些术语、接口和类的名字搞晕。代表要认证的token接口是o.s.s.core.Authentication,这个接口的实现将以后缀AuthenticationToken结尾。这是一个很简单的方式来区分Spring Security提供的认证实现类。】

在本例中,我们尽可能将错误检查最小化(译者注:即参数的合法性与完整性的检查)。可能在实际的应用中,会校验是否所有头信息都提供了以及在发现用户提供信息不正确的时候要抛出异常或对用户进行重定向。

一个细小的配置变化是需要将我们的过滤器插入到过滤器链中:

 

<http auto-config="true" ...>
  <custom-filter ref="requestHeaderFilter" 
  before="FORM_LOGIN_FILTER"/>
</http>

 你可以看到过滤器代码最后请求AuthenticationManager来进行认证。这将最终委托配置的AuthenticationProvider,它们中的一个要支持检查SignedUsernamePasswordAuthenticationToken。接下来,我们需要书写一个AuthenticationProvider来做这件事情。

实现基于请求头的AuthenticationProvider

现在,我们写一个AuthenticationProvider的实现类,即com.packtpub.springsecurity.security.SignedUsernamePasswordAuthenticationProvider,负责校验我们自定义Authentication token的签名。

 

package com.packtpub.springsecurity.security;
// imports omitted
  public class SignedUsernamePasswordAuthenticationProvider 
  extends DaoAuthenticationProvider {
    @Override
    public boolean supports(Class<? extends Object> authentication) {
      return (SignedUsernamePasswordAuthenticationToken .class.isAssignableFrom(authentication));
    }
  @Override
  protected void additionalAuthenticationChecks 
  (UserDetails userDetails,
    UsernamePasswordAuthenticationToken authentication)
    throws AuthenticationException {
    super.additionalAuthenticationChecks 
    (userDetails, authentication);
    SignedUsernamePasswordAuthenticationToken signedToken = 
      (SignedUsernamePasswordAuthenticationToken) authentication;
    if(signedToken.getRequestSignature() == null) {
      throw new BadCredentialsException(messages.getMessage(
      "SignedUsernamePasswordAuthenticationProvider
      .missingSignature", "Missing request signature"),
      isIncludeDetailsObject() ? userDetails : null);
    }
// calculate expected signature 
  if(!signedToken.getRequestSignature() 
  .equals(calculateExpectedSignature(signedToken))) {
  throw new BadCredentialsException(messages.getMessage 
  ("SignedUsernamePasswordAuthenticationProvider 
  .badSignature", "Invalid request signature"),
  isIncludeDetailsObject() ? userDetails : null);
  }
}
private String calculateExpectedSignature 
  (SignedUsernamePasswordAuthenticationToken signedToken) {
    return signedToken.getPrincipal() + "|+|" + 
    signedToken.getCredentials();
  }
}

 你可以看到我们再次扩展了框架中的类DaoAuthenticationProvider,因为有用的数据访问代码仍然需要进行实际的用户密码校验以及通过UserDetailsService加载UserDetails

         这个类有些复杂,所以我们将分别介绍其中的每个方法。

         Supports方法,是重写父类的方法,向AuthenticationManager指明当前AuthenticationProvider要进行校验的期望运行时Authentication token

         接下来,additionalAuthenticationChecks方法被父类调用,此方法允许子类对token进行特有的校验。这正适合我们的策略,所以添加上我们对token新的签名检查。基本上已经完成了我们自定义“简单SSO”的实现,仅剩一处配置了。

连接AuthenticationProvider

         一个常见的要求就是将一个或更多的AuthenticationProvider接口连接起来,因为用户可能会以几种校验方式中的某一种登录系统。

因为到目前为止,我们还没有了解其它的AuthenticationProvider,我们可以假设以下的需求,即使用标准的用户名和密码基于form的认证以及前面实现的自定义简单SSO认证。当配置了多个AuthenticationProvider时,每个AuthenticationProvider都会检查过滤器提供给它的AuthenticationToken,仅当这个token类型它支持时才会处理这个token。以这种方式,你的应用同时支持不同的认证方式并不会有什么坏处。

连接多个AuthenticationProvider实际上很简单。只需要在我们的dogstore-security.xml配置文件中声明另一个authentication-provider引用。

 

<authentication-manager alias="authenticationManager">
  <authentication-provider ref= "signedRequestAuthenticationProvider"/>
  <authentication-provider user-service-ref="jdbcUserService">
    <password-encoder ref="passwordEncoder" >
      <salt-source ref="saltSource"/>
    </password-encoder>
  </authentication-provider>
</authentication-manager>

          与我们安全配置文件中引用的其它Spring bean一样,signedRequestAuthenticationProvider引用就是我们的AuthenticationProvider,它将在dogstore-base.xml中与其它的Spring bean一起进行配置。

 

<bean id="signedRequestAuthenticationProvider"  class="com.packtpub.springsecurity.security 
.SignedUsernamePasswordAuthenticationProvider">
  <property name="passwordEncoder" ref="passwordEncoder"/>
  <property name="saltSource" ref="saltSource"/>
  <property name="userDetailsService" ref="jdbcUserService"/>
</bean>

 我们自定义的AuthenticationProviderbean属性其实都是父类所需要的。这些也都指向了我们在AuthenticationManager的中第二个authentication-provider声明中的那些bean

         最终已经完成了支持这个简单单点登录功能的编码和配置,至此可以给自己一个小小的喝彩。但是,还有一个小问题——我们应该怎样操作请求的http头以模拟我们的SSO认证提供者呢?

使用请求头模拟单点登录

         尽管我们的场景比较牵强,但是有一些商业和开源的单点登录解决方案,它们能够被配置以通过HTTP请求头发送凭证信息,最具有代表性的是CA(以前的NetegritySiteMinder

【需要特别注意的是,与SSO方案集成的应用是不能通过用户的直接请求访问的。通常情况下,SSO provider功能作为代理,通过它确定用户的请求流程(是安全的)或provider持有关于密码的信息并将这些信息与单个的安全应用隔离。在没有完全了解一个其使用的硬件、网络和安全设施之前,不要部署SSO应用。】

         Mozilla Firefox的浏览器扩展,名为Modify Headers(可以在以下地址获得:http://modifyheaders.mozdev.org),是一个很简单的工具能够用来模拟伪造HTTP头的请求。以下的截图表明了如何使用这个工具添加我们的SSO方案所希望得到的请求头信息:



 将所有的头信息标示为Enabled,访问这个URLhttp://localhost:8080/JBCPPets/j_spring_security_filter,会发现我们能够自动登录系统。你可能也会发现我们给予form的登录还能继续可用,这是因为保留了这两个AuthenticationProvider实现以及过滤器链中对应的过滤器。

(译者注:说实话,作者这个实现自定义AuthenticationProvider的例子真的是比较牵强,但是还算完整描述出了其实现方式,想深入了解AuthenticationProvider自定义的朋友,可以参照Spring Security提供的CasAuthenticationProvider等实现。)

实现自定义AuthenticationProviders时要考虑的事项

         尽管我们刚刚看到的例子并没有阐述你想构建的AuthenticationProvider,但是任何自定义AuthenticationProvider的步骤是类似的。这个练习的关键在于:

l  基于用户的请求完成一个Authentication实现的任务一般情况下会在过滤器链中的某一个中进行。取决于是否校验凭证的数据,这个校验组件可能要进行扩展;

l  基于一个合法的Authentication认证用户的任务需要AuthenticationProvider的实现来完成。请查看我们在第二章中讨论过的AuthenticationProvider所被期望拥有的功能;

l  在一些特殊的场景下,如果未认证的session被发现,可能会需要自定义的AuthenticationEntryPoint。我们将会在本章接下来的部分更多了解这个接口,也会在第十章介绍中心认证服务(CAS)时,介绍一些AuthenticationEntryPoint的实际例子。

如果你能时刻记住它们的角色,当你在开发应用特定的AuthenticationProvider时,会在实现和调试过程中少很多的迷惑。

  • 大小: 53.2 KB
  • 大小: 82.3 KB
2
3
分享到:
评论
1 楼 vipandace 2013-09-29  
你好 , 我刚接触security 看了你添加的这个provider的过程,想问一下 ,如果这样认证成功后 页面跳转到哪呢,或者说能不能自定义返回的数据呢?求解答~~谢谢

相关推荐

    Spring Security3中文文档

    ### 第二章:深入理解Spring Security3 本章深入探讨了Spring Security3的内部机制,包括安全过滤器链、认证管理器(Authentication Manager)的工作原理以及如何定制这些组件以满足特定需求。 ### 第三章:高级安全...

    springsecurity学习笔记

    在"springsecurity学习笔记"中,你可能会涉及以下主题: - Spring Security的基本配置,包括web安全配置和全局安全配置。 - 如何自定义认证和授权流程,比如实现自定义的AuthenticationProvider和...

    spring security 官方文档

    9. **自定义**:Spring Security非常灵活,允许开发者根据需求自定义大部分组件,如访问决策管理器、权限评估器等,以满足特定业务场景。 10. **与其他Spring框架的集成**:Spring Security与Spring Boot、Spring ...

    spring security 3.x第五章例子

    Spring Security 是一个强大的和高度可定制的身份验证和...总的来说,Spring Security 3.x第五章的实例将帮助开发者深入理解这个框架的使用,通过具体的代码示例来实践安全性配置,从而更好地保护他们的Spring应用。

    SpringMVC集成SpringSecurity

    2. **集成过程**:在SpringMVC项目中集成SpringSecurity,首先需要在pom.xml文件中引入相应的依赖,接着配置SpringSecurity的XML配置文件,定义安全规则、用户认证方式等。 3. **默认账户和密码**:“admin,admin...

    SpringBoot + SpringSecurity + JPA 实现用户角色权限登录认证

    在SpringSecurity的配置中,会定义一个自定义的AuthenticationProvider来处理用户的登录认证,以及UserDetailsService来获取用户信息。此外,还需要配置HttpSecurity以拦截特定URL,根据用户的角色和权限决定是否...

    SpringSecurity素材.zip

    6. **CSRF防护(Cross-Site Request Forgery)**:SpringSecurity提供了内置的CSRF防护,通过生成和验证CSRF令牌,防止恶意第三方发起未经授权的操作。 7. **密码加密**:SpringSecurity支持多种密码加密策略,包括...

    spring-security 案例

    - **自定义AuthenticationProvider**:如果需要使用非默认的验证逻辑,可以创建自己的AuthenticationProvider。 - **自定义UserDetailsService**:处理用户详情,从数据库或其他来源加载用户信息。 6. **异常处理...

    Spring Security 小例子(1)

    8. **OAuth2集成**:Spring Security还支持OAuth2协议,允许第三方应用获取有限的访问权限到受保护的资源,增强了现代Web应用的安全性和灵活性。 在“SpringSecurityDemo”这个示例项目中,你可能会看到如何配置...

    springsecurity3离线手册

    本离线手册是SpringSecurity 3版本的详细指南,对于开发者来说,是一份非常宝贵的参考资料。 在SpringSecurity 3中,主要包含了以下几个核心概念: 1. **认证(Authentication)**:这是验证用户身份的过程。...

    SpringSecurity3框架

    - Spring Security 3支持OAuth2协议,可以用于实现第三方登录功能,如Google、Facebook登录。 8. **AOP集成** - Spring Security利用Spring的AOP(面向切面编程)实现方法级别的安全控制,可以对方法调用进行访问...

    spring-security3 入门篇

    - **OAuth2集成**: 如何使用Spring Security与OAuth2结合,实现第三方登录功能。 - **CORS支持**: 设置跨域请求的安全策略,允许不同源的Web应用进行交互。 - **国际化的错误处理**: 如何定制Spring Security的...

    spring_security.zip

    例如,可以使用OAuth2 实现第三方登录,Spring Security 处理内部认证和授权。 2. **授权服务器**:Spring Security 提供OAuth2 提供者支持,可以搭建自己的授权服务器,实现令牌的颁发和验证。 3. **保护API**:在...

    spring-security-2.0.5

    用户可以通过自定义AuthenticationProvider实现自己的认证逻辑,确保用户身份的正确性。 - **授权**:Spring Security的访问决策管理器(Access Decision Manager)支持基于角色、基于权限和自定义策略的授权。Role-...

    SpringSecurity实现的权限管理(含包)

    6. **SpringSecurity的包结构**:在提供的"ss3"压缩包中,可能包含了SpringSecurity的相关库文件,如spring-security-config、spring-security-core、spring-security-web等。这些库提供了实现上述功能所需的所有类...

    spring security 参考手册中文版

    第二部分 架构与实现 73 9.技术概述 73 9.1运行环境 73 9.2核心组件 74 9.2.1 SecurityContextHolder,SecurityContext和认证对象 74 获取有关当前用户的信息 75 9.2.2 UserDetailsService 75 9.2.3授予权力 77 ...

    springsecurity框架

    10. **OAuth2集成**:SpringSecurity可以与OAuth2框架集成,实现第三方登录、API保护等功能。 通过理解以上核心概念,开发者能够更好地利用SpringSecurity为应用程序构建稳固的安全防护。在实践中,根据项目需求...

    spring-security3.1源码

    6. **OAuth支持**:虽然3.1版本的OAuth支持可能相对有限,但Spring Security已经开始提供对OAuth协议的基础支持,允许应用与其他OAuth服务器进行交互,提供资源保护和第三方应用授权。 7. **XML和Java配置**:...

    Spring Security 3.1.pdf

    1. **易于集成**:Spring Security 3.1 作为 Spring 生态系统的一部分,与其他 Spring 组件有着良好的集成性。 2. **灵活性**:Spring Security 3.1 提供了大量的扩展点,使得开发者可以根据实际需求进行定制化开发...

Global site tag (gtag.js) - Google Analytics