在上一篇文章中我们给大家介绍了OAuth2授权标准,并且着重介绍了OAuth2的授权码认证模式。目前绝大多数的社交媒体平台,都是通过OAuth2授权码认证模式对外开放接口(登录认证及用户信息接口等)。但是,我们也看到OAuth2有一定的复杂性,如果所有的代码都由我们自己开发,还是有一定的工作量的。因此,我们完全可以使用Spring Social帮助我们,Spring Social对OAuth2标准进行了完整友好的封装。
本文就通过对Spring Social源码进行一下解析,从而在我们后续开发第三方媒体平台的登录认证功能时,能更加的清晰。

一、Spring Social结构化角度解析源码

Spring Social是一个帮助我们连接社交媒体平台,方便在我们自己的应用上开发第三方登录认证等功能的Spring 类库。其中比较核心的类和接口,如下图所示,我们来一一解析。

首先我们简单回顾一下OAuth2,OAuth2主要包含两部分内容:认证和鉴权。

  • 认证过程就是通过用户授权,获取授权码,最终换取AccessToken的过程。这个过程是标准的OAuth2认证流程,所有平台都遵循,可以认为是一致的。
  • 鉴权过程就是携带AccessToken访问社交媒体平台API接口。当然各平台的用户不同、业务不同,所以提供的的接口不一样。

如果你对这部分内容,还不是很熟悉,先回看我的上一篇文章。请结合下面的这张图理解后面的文字。

1.1.OAuth2认证源码

首先在实现OAuth2登录认证的过程中,有多次我们自己开发的应用和社交媒体平台之间的的请求和响应。所以我们需要封装一个类用来处理标准的OAuth2认证专用的HTTP工具类,这个可以说是最重要的工作,Spring Security已经帮我们提供了OAuth2Operations接口,其默认的实现类是OAuth2Template,根据不同的平台的实现差异我们可能会需要自己来实现(微调)。认证过程中所有与OAuth2认证服务器交互的工作就全交给OAuth2Operations,最后返回给我们一个AccessToken。


对于开发者来说,只要将以上四个属性的值告诉OAuth2Operations。只要服务提供商是严格按照OAuth2标准开发的认证服务,剩下的与认证服务器交互的过程,我们就不需要处理了。

1.2.接口资源鉴权

当我们获得了AccessToken之后,就有权限请求OAuth2资源服务器里面的资源了。各个社交媒体平台根据用户及业务不同提供的接口完全不同,这时我们需要用到RestTemplate,通用的HTTP工具类处理请求与响应。从图中可以看到,处理各种数据格式JSON、XML的类库,RestTemplate会自行根据环境判断使用哪一个。


那既然各个平台的业务接口各不相同,我们当然要自定义开发不同的接口实现APIImpl。此时我们应该需要一个统一的父类,包含accessToken和RestTemplate,这样我们的自定义接口实现就可以通过继承这个类获得并使用accessToken和RestTemplate。这个统一的父类叫做AbstractOAuth2Binding。它还帮助我们实现HTTP请求的参数携带,以及请求结果到对象的反序列化工作等。

至此,OAuth2Operations 和 自定义接口实现APIImpl,一个负责认证流程请求响应,一个负责资源请求响应。二者统一被封装为ServiceProvider-服务提供商。

1.3.确定用户关系

通过实现上面的代码中的接口,我们自己的应用与社交媒体平台(服务提供商)的HTTP交互过程就已经可以被全部支持了。但是开发社交媒体登陆还有一个很重要的步骤就是:判定社交媒体平台响应的用户信息与我们自己的应用用户之间的关系。我们用一张数据库表来表示这个关系,而且必须是这张表(Spring Social专用,在spring-social-core包里面可以找到):

create table UserConnection (
    userId varchar(255) not null,
    providerId varchar(255) not null,
    providerUserId varchar(255),
    rank int not null,
    displayName varchar(255),
    profileUrl varchar(512),
    imageUrl varchar(512),
    accessToken varchar(512) not null,
    secret varchar(512),
    refreshToken varchar(512),
    expireTime bigint,
    primary key (userId, providerId, providerUserId));
create unique index UserConnectionRank on UserConnection(userId, providerId, rank);

这张表中,最重要的三个字段就是userId(自开发应用的用户唯一标识),provider(服务提供商,社交媒体平台唯一标识),providerUserId (服务提供商用户的唯一标识)。通过这三个字段体现自开发应用的用户与服务提供商用户之间的关系,从而判定服务提供商的用户是否可以通过OAuth2认证登录我们的应用。(这张表里面的数据,是通过注册或者绑定操作加入进去的,与认证、鉴权过程无关)

  • 通过1.2小节中的接口,我们可以获得社交媒体的用户的数据User,但是我们说过了这个User在不同的服务提供商平台上,其结构是完全不同的。而spring Social只认识一种用户的数据结构,那就是Connection(OAuth2Connection)。所以我们需要一个ApiAdapter帮我们将二者进行适配。ApiAdapter是一个接口,内容需要我们自行实现。
  • 现在我们拿到了Spring Social认可的服务提供商用户信息Connection,然后使用Connection加载UserId(我们自己开发的平台的userid)。如果能够加载到userId(不为空),表示登录验证成功。

1.4.本地应用授权

通过实现上面代码中的接口,我们就可以拿到userId,我们自己开发的应用的用户的唯一标识。也表示利用社交媒体用户登录我们自己开发的应用成功了。但是,还有一个问题没有解决,你是登陆成功了,但是不意味着你可以访问本地应用中的所有资源。所以,我们根据userId查找当前用户,并为他赋权。

在我们之前的使用用户名密码登陆的案例中,是通过实现UserDetailsService和UserDetails接口来实现的。在社交媒体登录过程中,我们需要实现的接口是SocialUserDetailsService和SocialUserDetails。其实实现原理是一样的,就是用用户的唯一标识userId,加载该用户角色的权限信息。至此,Spring Security就知道了该用户的权限信息,可以有效的控制其访问权限。

二、Spring Social流程角度解析源码

Spring Social自动配置会在过滤器链中加入一个SocialAuthenticationFilter过滤器,该过滤器拦截社交媒体登录请求。


SocialAuthenticationFilter过滤器拦截的社交媒体登录请求的地址是{filterProcessesUrl}/{providerId}。filterProcessesUrl的默认值是“/auth”,如果你的服务提供商providerId(自定义)是github,那么你的社交媒体登录按钮请求的地址就应该是“/auth/github”,当然这两个值我们都可以修改。

要说明的是{filterProcessesUrl}/{providerId}在Spring Social既是认证请求的地址,也是服务提供商回调的地址。当用户点击"github登录"按钮,此时访问/{filterProcessesUrl}/{providerId}被拦截,此时用户没有被认证通过,所以跳转到GitHub授权页面(authorizeUrl)上,用户输入用户密码授权,在浏览器跳回到本地应用,仍然回到/{filterProcessesUrl}/{providerId}再次被拦截。


首先要检测用户是否授权使用第三方平台用户信息,如果没授权就直接抛出异常。如果用户授权了,就去执行OAuth2一系列的请求响应,获取授权码、AccessToken、Connection用户信息。这个过程代码在OAuth2AuthenticationService中被定义。


doAuthentication中授权过程,参考1.3、1.4小节内容。如果授权失败(该社交平台用户在本地应用中没有对应的用户),则跳转到signUpUrl。执行注册即用户关系绑定业务逻辑。

注意:Spring Social实现的OAuth2认证鉴权流程中,使用到了session(如上图中的sessionStrategy代码)。所以当你的应用是一个无状态应用时,需要对Spring Social进行一定程度的改造。但是笔者从来没这么做过。简单的做法就是:使用session开发有状态应用,并且session保存的状态信息交给redis集中管理;或者开发无状态应用之前,确定该应用不需要社交媒体登录功能,比如某企业内网应用。

期待您的关注

社交媒体登录Spring Social的源码解析的更多相关文章

  1. Spring Security 解析(七) —— Spring Security Oauth2 源码解析

    Spring Security 解析(七) -- Spring Security Oauth2 源码解析   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...

  2. spring boot @Value源码解析

    Spring boot 的@Value只能用于bean中,在bean的实例化时,会给@Value的属性赋值:如下面的例子: @SpringBootApplication @Slf4j public c ...

  3. Feign 系列(05)Spring Cloud OpenFeign 源码解析

    Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...

  4. Spring Security 访问控制 源码解析

    上篇 Spring Security 登录校验 源码解析  分析了使用Spring Security时用户登录时验证并返回token过程,本篇分析下用户带token访问时,如何验证用户登录状态及权限问 ...

  5. 异步任务spring @Async注解源码解析

    1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...

  6. Spring @Import注解源码解析

    简介 Spring 3.0之前,创建Bean可以通过xml配置文件与扫描特定包下面的类来将类注入到Spring IOC容器内.而在Spring 3.0之后提供了JavaConfig的方式,也就是将IO ...

  7. api网关揭秘--spring cloud gateway源码解析

    要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux. 1.gateway 和zuul对比 I am the au ...

  8. Spring容器启动源码解析

    1. 前言 最近搭建的工程都是基于SpringBoot,简化配置的感觉真爽.但有个以前的项目还是用SpringMvc写的,看到满满的配置xml文件,却有一种想去深入了解的冲动.折腾了好几天,决心去写这 ...

  9. Java工程师学习指南第3部分:Spring与SpringMVC源码解析

    本文整理了微信公众号[Java技术江湖]发表和转载过的Spring全家桶优质文章,想看到更多Java技术文章,就赶紧关注吧. 前后端分离,我怎么就选择了 Spring Boot + Vue 技术栈? ...

随机推荐

  1. 7.30 NOIP模拟10

    T1.辣鸡 考试的时候竟然被我以“麻烦”弃掉了,赛后发现这题好水啊,直接sort一下寻找四周即可. T2.模板 考试时期望得分70,实际得分5 首先看到这种题基本就是线段树,我们以时间为下标,对每一个 ...

  2. 记录一些html5和css3的一部分属性

    html5 标签1 video:视频 属性: src:视频的url autoplay:视频在就绪后马上播放 controls:向用户显示控件2 audio:音频 属性类似于video3 属性:drag ...

  3. 原生JS实现队结构及利用队列模拟‘击鼓传花’游戏

    1. 前言 队列,是一种遵从先进先出(FIFO,First-In-First-Out)原则的有序集合.队列在尾部添加新元素,并从顶部移除元素,最新添加的元素必须排在队列的末尾. 2.功能说明 enqu ...

  4. 005.Kubernetes二进制部署kubectl

    一 部署 kubectl 1.1 安装kubectl [root@k8smaster01 ~]# cd /opt/k8s/work [root@k8smaster01 work]# wget http ...

  5. haproxy+keepalived练习

    小的网站结构 说明:如果部署在云上,比如阿里云上,不需要自己部署keepalived,直接买阿里云的slb即可,slb然后分发流量到两台haproxy机器 一.先部署两个web服务器 编译安装ngin ...

  6. nyoj 14-会场安排问题 (贪心)

    14-会场安排问题 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:9 submit:15 题目描述: 学校的小礼堂每天都会有许多活动,有时间这些活动 ...

  7. hdu 2444 The Accomodation of Students (判断二分图,最大匹配)

    The Accomodation of StudentsTime Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  8. MemoryStream相关知识分享

    一.简单介绍一下MemoryStream MemoryStream是内存流,为系统内存提供读写操作,由于MemoryStream是通过无符号字节数组组成的,可以说MemoryStream的性能可以算比 ...

  9. C语言1博客作业01

    1 你对软件工程专业或者计算机科学与技术专业了解是怎样? 主修大数据技术导论.数据采集与处理实践(Python).Web前/后端开发.统计与数据分析.机器学习.高级数据库系统.数据可视化.云计算技术. ...

  10. 浅谈Linux中的各种锁及其基本原理

    本文首发于:https://mp.weixin.qq.com/s/Ahb4QOnxvb2RpCJ3o7RNwg 微信公众号:后端技术指南针 0.概述 通过本文将了解到如下内容: Linux系统的并行性 ...