深刻理解基于OAuth2.0&第三方登陆之GitHub实践

基于OAuth2.0的第三方登陆

第三方登陆的实质

第三方登陆的实质,就是在OAuth2.0协议的基础上,利用外部的标识来获取账号的内部标识而后完成登陆的过程。
具体的讲,就是将三方的账号绑定到产品自身的账号上,当查询到用户第三方的账号已经绑定了平台的某个user_id时,直接登陆对应的账号。例如利用微信QQ快捷登录,能够不用注册APP帐号,先点击跳转到微信,再点击受权进去APP中。git

几个重要概念

1)外部标识
用来使用用户身份的标志,能够是用户名,手机号,邮箱等,每个外部标识必定和一个内部标识相关联用以肯定一个用户。
外部标识的做用有两个github

  1. 让用户经过本身熟知且占有的外部标识来登陆产品
  2. 能够经过校验外部标识来实现找回或转移数据资产

2)内部标识
即产品中用于标识用户惟一性的标志,例如user_id,必须有,不可更改且惟一,用户通常接触不到内部标识。
当一个内部标识创建后,用户全部的数据资产都会绑定到这个内部标识上。web

3)user_id
一个经常使用的内部标识,相似你的18位身份证IDspring

4)app_id
用于区别不一样APP的ID,具备惟一性。后端

5)open_id
第三方平台为了用户信息的安全,通常不会直接将用户的内部标识给到其余产品,而是选择了给一个外部标识,这个open_id就是微信给各个APP用以区分微信用户身份的外部标识。api

6)union_id
不一样的产品的可使用同一个union_id来确认用户的身份。浏览器

7)access_token
能够理解为通行证,有了这个通行证,就能获取到第三方平台指定用户的有限信息。安全

8)OAuth 2.0
OAuth2.0就是客户端和认证服务器之间因为相互不信任而产生的一个受权协议,只要受权方和被受权方遵照这个协议去写代码提供服务,那双方就是实现了OAuth2.0模式。服务器

为何须要加入第三方登陆

  1. 提升登陆转化率,登陆更加快捷,不须要输入密码
  2. 提升注册转化率,注册更加快速,方便获取用户信息
  3. 信赖感(让用户以为这个产品和大厂是有合做的,提升对产品的信赖感)

OAuth2.0协议规范流程

在这里插入图片描述
(1) Client请求RO的受权,请求中通常包含:要访问的资源路径,操做类型,Client的身份等信息。
(2) RO批准受权,并将“受权证据”发送给Client。至于RO如何批准,这个是协议以外的事情。典型的作法是,AS提供受权审批界面,让RO显式批准。这个能够参考下一节实例化分析中的描述。
(3) Client向AS请求“访问令牌(Access Token)”。此时,Client需向AS提供RO的“受权证据”,以及Client本身身份的凭证。
(4) AS验证经过后,向Client返回“访问令牌”。访问令牌也有多种类型,若为bearer类型,那么谁持有访问令牌,谁就能访问资源。
(5) Client携带“访问令牌”访问RS上的资源。在令牌的有效期内,Client能够屡次携带令牌去访问资源。
(6) RS验证令牌的有效性,好比是否伪造、是否越权、是否过时,验证经过后,才能提供服务。微信

最典型的Authorization Code 受权模式

在这里插入图片描述
核心思想:
oauth 的核心思想就是要让第三方在不知道用户名密码的状况下完成鉴权,可是没有密码用户名组合根本不可能有效鉴权, oauth 实际的过程是一个李代桃疆的手法。在第一方用你的原始用户名和密码组合,生成另一对名称密码组合,这个阶段叫作获取 code 和 state,这对组合送到第二方也就是你的资源所在地,一样较验一遍,若是合格,给你生成一个带有时效性的 access token, 第三方在有效期内拿着这个 access token 跳过第一方直接请求第二方的资源,至于为何不直接返回 access token?
是由于若是使用 code 方式的话,服务器得到用户受权后经过 302 跳转到你的 callback URI 上,并在 url query 上带上用于交换 accesd token 的 code ,你在浏览器地址栏就能够看到这个code ,已经暴露有可能被不法应用,因此在 url 上直接返回 access token 是不安全的,而client拿到code之后换取access token是client后台对认证服务器的访问,而且须要clientID和client secret,不依赖浏览器,access token不会暴露出去。

为什么引入authorization_code?

由于单从OAuth2.0的受权过程来看,若是直接返回access_token,协议将变得更加简洁,并且少一次Client与AS之间的交互,性能也更优,其实否则。引入authorization_code有不少妙处,主要缘由以下:

  1. 浏览器的redirect_uri是一个不安全信道,此方式不适合于传递敏感数据(如access_token),会显著扩大access_token被泄露的风险。
    但authorization_code能够经过redirect_uri方式来传递,是由于authorization_code并不像access_token同样敏感。
    即便authorization_code被泄露,攻击者也没法直接拿到access_token,由于拿authorization_code去交换access_token是须要验证Client的真实身份。

  2. 因为协议须要验证Client的身份,若是不引入authorization_code,这个Client的身份认证只能经过第1步的redirect_uri来传递。一样因为redirect_uri是一个不安全信道,这就额外要求Client必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。
    引入authorization_code以后,AS能够直接对Client进行身份认证(见步骤4和5),并且能够支持任意的Client认证方式(好比,简单地直接将Client端密钥发送给AS)。

OAuth 协议设计不一样于简单的网络安全协议的设计,由于OAuth须要考虑各类Web攻击,好比CSRF (Cross-Site Request Forgery), XSS (Cross Site Script), Clickjacking。
在redirect_uri中引入state参数就是从浏览器安全角度考虑的,有了它就能够抵制CSRF攻击。

第三方登陆之GitHub实践

开发以前,须要前往第三方登陆的开发者平台QQ、新浪微博、Github,注册帐号并填写信息申请接入,成功后会给你一个ID和秘钥,之后你就经过该ID和秘钥来获取令牌,从而实现第三方登陆。申请ID和秘钥时Github不须要审核,因此本文主要介绍GitHub实践。QQ、微信、微博等须要审核,但流程和原理都是同样的。

Register a new OAuth application

登录我的GitHub帐号,进入【Settings】->选择【applications】->选择【Developer applications】-> 【Register a new OAuth application】

填写必要信息

注册以后会获得 github提供的client id和client secret

以Github为例,其相应的API地址分别为:
https://github.com/login/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&state={state}
http://localhost:8888/oauth/github/callback?code={code}&state={state}
https://github.com/login/oauth/access_token
https://api.github.com/user?access_token={access_token}
若是要写

如今,咱们须要作下列事情:

  • 在首页显示Github的受权连接,使用户可以访问authorizationUrl
  • 编写一个Controller,处理http://localhost:8888/oauth/github/callback?code={code}&state={state}的请求,主要是拿到code
  • 用code访问http://localhost:8888/oauth/github/callback?code={code}&state={state}access
    token
  • 而后利用access token访问https://api.github.com/user?access_token={access_token},拿到用户信息

引入必要的依赖,就能够开发了,前期代码写的有些繁琐,后来发现巧妙使用配置文件application.yml中会更加简洁,由于Spring已经整合好了整个Oauth2.0流程,能够减小了不少代码。
逻辑代码就不具体展现了,重中之重的配置文件application.yml内容以下

github-base-url: https://github.com/login

spring:
	security:
		oauth2:
			client:
				registration:
					github:
						client-id: 4255eebca50558bd0579(Your client-id)
						client-secret: XXXXX(Your client-secret)
						authorizationGrantType: authorization_code
						redirect_uri_template: "{baseUrl}/login/oauth2/code/{registrationId}"
						clientName: github-client
				provider:
					github:
						token-uri: ${github-base-url}/oauth/access_token
						authorization-uri: ${github-base-url}/oauth/authorize
						user-info-uri: https://api.github.com/user
server:
port: 8888

GitHub完成受权验证的大体流程

在这里插入图片描述
1.用户点击github登陆本地应用引导用户跳转到第三方受权页
跳转地址:https://github.com/login/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&state={state}

client_id,client_secret是注册好Oauth APP后github提供的,须要写在本地代码或者配置文件中,state也是在本地生成的。redirect_uri 就是在GitHub官网填的Authorization callback URL。

此时带着state等参数去申请受权,但此时还没有登录,未能经过authorize,GitHub返回code参数。

2.受权成功后会重定向带参数访问上面的redirect_uri,并多了一个code参数
后台接收code这个参数,咱们带着这个code再次访问github 地址
https://github.com/login/oauth/access_token?client_id=xxx&client_secret=xxx&code=xxx&redirect_uri=http://127.0.0.1:8080/cqput-bbs/User/RegisteredByGithub.do

3.经过state参数和code参数,成功获取access_token
有了access_token,只须要把access_token参数放在URL后面便可,就能够换取用户信息了。
访问地址:https://api.github.com/user?access_token=xxx;

4.获得github受权用户的我的信息,就代表受权成功

整个流程相似于下图,放在这里方便你们理解。
在这里插入图片描述

总结

本文主要是结合本身所学知识,和众多参考资料,探讨了本身对OAuth2.0原理和第三方登陆实质的一些理解,完成了第三方登陆之GitHub的实践。 但愿能对你们有所帮助~ 有问题欢迎留言交流,不足之处还请多多指正。

相关文章
相关标签/搜索