前言
基于SpringCloud做微服务架构分布式系统时,OAuth2.0作为认证的业内标准,Spring Security OAuth2也提供了全套的解决方案来支持在Spring Cloud/Spring Boot环境下使用OAuth2.0,提供了开箱即用的组件。但是在开发过程中我们会发现由于Spring Security OAuth2的组件特别全面,这样就导致了扩展很不方便或者说是不太容易直指定扩展的方案,例如:
- 图片验证码登录
- 短信验证码登录
- 微信小程序登录
- 第三方系统登录
- CAS单点登录
在面对这些场景的时候,预计很多对Spring Security OAuth2不熟悉的人恐怕会无从下手。基于上述的场景要求,如何优雅的集成短信验证码登录及第三方登录,怎么样才算是优雅集成呢?有以下要求:
- 不侵入Spring Security OAuth2的原有代码
- 对于不同的登录方式不扩展新的端点,使用/oauth/token可以适配所有的登录方式
- 可以对所有登录方式进行兼容,抽象一套模型只要简单的开发就可以集成登录
基于上述的设计要求,接下来将会在文章种详细介绍如何开发一套集成登录认证组件开满足上述要求。
阅读本篇文章您需要了解OAuth2.0认证体系、SpringBoot、SpringSecurity以及Spring Cloud等相关知识
思路
我们来看下Spring Security OAuth2的认证流程:
这个流程当中,切入点不多,集成登录的思路如下:
- 在进入流程之前先进行拦截,设置集成认证的类型,例如:短信验证码、图片验证码等信息。
- 在拦截的通知进行预处理,预处理的场景有很多,比如验证短信验证码是否匹配、图片验证码是否匹配、是否是登录IP白名单等处理
- 在UserDetailService.loadUserByUsername方法中,根据之前设置的集成认证类型去获取用户信息,例如:通过手机号码获取用户、通过微信小程序OPENID获取用户等等
接入这个流程之后,基本上就可以优雅集成第三方登录。
实现
介绍完思路之后,下面通过代码来展示如何实现:
第一步,定义拦截器拦截登录的请求
/**
* @author LIQIU
* @date 2018-3-30
**/
@Component
public class IntegrationAuthenticationFilter extends GenericFilterBean implements ApplicationContextAware {
private static final String AUTH_TYPE_PARM_NAME = "auth_type";
private static final String OAUTH_TOKEN_URL = "/oauth/token";
private Collection<IntegrationAuthenticator> authenticators;
private ApplicationContext applicationContext;
private RequestMatcher requestMatcher;
public IntegrationAuthenticationFilter(){
this.requestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher(OAUTH_TOKEN_URL, "GET"),
new AntPathRequestMatcher(OAUTH_TOKEN_URL, "POST")
);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if(requestMatcher.matches(request)){
//设置集成登录信息
IntegrationAuthentication integrationAuthentication = new IntegrationAuthentication();
integrationAuth