JHipster Study Default Authentication Method

摘要:本文主要通过研究 JHipster 默认的登陆授权机制,学习 Spring-Security 基础知识。通过注解配置基于 DAO 的验证方法。

参考链接

由于 Spring 支持配置的方法非常灵活,所有同一个功能会有各种各样的配置方法,所以在网上搜索资料的时候,需要灵活的理解不同配置方法。

首先列出相关的参考文档和知识点:

Spring Security 官网文档:

6.9 Authentication:UserDetailsService : 这是其中的一种授权方法,比较灵活,只需要提供一个 UserDetailsService 接口的实现,然后进行相应的配置,该节只是简单的介绍,并没有详细其实现和配置方法。
8.2 UserDetailsService Implementation :这一小节详细的介绍了其实现和配置方法,从原理上分析,推荐阅读
Spring Security: Authentication with a Database-backed UserDetailsService :比较精准扼要的介绍使用方法,实用,并且提供了另种配置方法。但是注解配置和 JHipster 不太一样。

验证概述

上图是一张高度概括的 Spring Security Authentication 的架构,我们这里根据 JHipster 的实现具体的介绍一下。

以下简要介绍一下配置和实际验证的调用流程

  1. 授权 API 入口 UserJWTControllerauthorize 方法,该方法关于授权只用了两行代码
  2. 根据用户输入的 credential 创建 UsernamePasswordAuthenticationToken
  3. 使用 AuthenticationManager 的抽象方法 authenticate(authenticationToken) 授权。
  4. 抽象方法 authenticate 的实际调用是 ProviderManager 的实现方法,这个方法中,我们可以看到里面维护了一个 AuthenticationProvider 列表,然后依次使用每个 provider 进行验证操作。
  5. AuthenticationProvider 有一个抽象类实现 AbstractUserDetailsAuthenticationProvider,进而有一个 DaoAuthenticationProvider 非抽象实现类
  6. DaoAuthenticationProvider 中有一个成员变量就是 UserDetailService
  7. 具体这个成员变量如何在 authenticate 方法中使用,需要追溯到抽象类的 authenticate 的重载,UserDetails user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);,实现类通过重载这个方法,来定义不同的获取 UserDetails 的方法,获取了这个 user,就可以进行验证了,additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);,这里还有 pre 和 post 验证的触发。
  8. 我们再回到 DaoAuthenticationProvider 类中,对 retrieveUser 的重载,关键就是调用了 UserDetailsServiceloadUserByUsername 方法获取的 UserDetailsUserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); 所以我们自己写的代码就是实现接口 UserDetailsService 然后实现 loadUserByUsername 方法
  9. 所以 JHipster 中有一个使用 @Component 注入的实现:DomainUserDetailsService,来完成这个任务。
  10. 另外,我们在配置类 SecurityConfiguration 中,通过 Intellij 可以智能的看到其构造方法的注入,就可以定位到这个实现。