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