彻底搞明白OAuth2.0

Posted 哇牛笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了彻底搞明白OAuth2.0相关的知识,希望对你有一定的参考价值。

OAuth2.0介绍

传统的c/s认证模型中,客户端如果想要访问服务器上受保护的资源,需要首先获取资源所有者(即用户的)凭证,为了让第三方应用能访问到这些受保护的资源,资源所有者即用户就需要把他们的凭证(一般是用户名和密码)分享给第三方应用,这种方式有以下几个问题和限制:

  1. 第三方应用需要存储用户的的凭证如用户名和密码,以供以后再次访问用户资源时使用

  2. 服务端需要承担密码认证等一系列密码保护的风险

  3. 一旦把用户名密码给了第三方应用,就等于给了第三方应用很大的用户信息访问权限,这样风险很大。如果用户想收回授权,必须修改密码等

OAuth解决了上述一系列问题,OAtuth协议通过引入认证层把第三方应用和用户解耦,第三方应用如果想要访问资源服务器上的用户资源,不再是直接使用用户的用户名和密码,而是使用一套新的信任凭证,在用户允许的情况下,资源服务器给第三方应用发送该凭证

客户端不再是直接使用用户的用户名和密码,而是在用户同意的情况下,由认证服务器给第三方应用(client)发送一个access token, client使用该token可以在一定的时间内访问用户允许的某些资源

角色(roles)

resource owner 指用户

resource server 资源服务器

authorization server 授权服务器

client 客户端,这里指第三方应用

授权服务器与资源服务器通常可以是部署在一起。这两个角色指的是指开放登录服务(即提供用户账号信息)的的服务,如微博 qq 微信 github等

交互流程如下所示:

协议流程说明


A:客户端请求用户的许可,该认证请求可以是直接发送给用户,比如直接是让用户输入用户名密码,也可以是直接跳转到授权服务器(如微博 github等)让用户登录授权服务器上的账号信息

B:客户端得到用户的认证授权。

C:客户端使用授权服务器给的授权凭证去获取access_token(令牌)

D:授权服务器检测授权凭证(授权码)合法就返回令牌

EF:使用令牌请求受保护的用户资源


获取令牌的方式

要想使用支持登录服务的功能,首先需要到支持登录服务的平台(如github 微博 qq 微信等)去注册自己的应用。平台会给第三方应用两个身份识别码:客户端ID 和 客户端密钥串。就是我们常用的clientid 和 client secret

authorization-code(授权码)

授权码方式,是指第三方应用先申请得到一个授权码,然后使用该授权码去获取令牌。这种方式是使用最多也最安全的。授权码通过前端传送,令牌则储存在后端,所有与资源服务器的交互都是在后端完成的。所以这种方式适合于所有具有后端的额应用。并且前后端分离,也能避免令牌的泄漏。


1: 假设第三方应用A使用github的登录功能,首先A网站提供一个链接,用户点击后跳转到github,授权用户的gitub账号数据给A应用使用

https://github.com/oauth2.0/authorize?response_type=code&client_id=client_id&redirect_uri=callback&scope=read

reponse_type=code 表示要求返回授权码,

client_id 就是我们的应用在github上注册的应用id

redirect_uri: github同意或者拒绝后跳转到的网址

scope=read 授权范围,这里是只读


2:当用户在github上登录并点击同意授权后,就会跳转到redirect_uri指定的网址并返回一个授权码,如下所示

https://a.com/callback?code=Authorizationcode


3:A网站拿到授权码后,就可以在后台像github发起如下请求获取令牌

https://github.com/oauth2.0/token?client_id=client_id&client_secret=client_secret&grant_type=authorization_code&code=Authorizationcode&redirect_uri=callback


github收到这个获取令牌的请求后,校验通过就会颁发令牌,就是像redirect_uri 指定的网址发送一段json数据。格式如下

{"access_token":"ACCESS_TOKEEN","token_type":"bearer","expires_in":3000,"refresh_token":"REFRESH_TOKEN","scope":"read","uid":2222,"info":{}}

access_token就是令牌。

implicit

适用于没有后端的应用,令牌必须存储在前端。这种认证方式就没有授权码一说了,而是直接获取令牌

1 https://github.com/oauth2.0/authorize?response_type=token&client_id=client_id&redirect_uri=callback&scope=read

reponse_type=token 表示直接获取令牌

2 github直接把令牌返回  跳转到redirecrt_uri中指定的网址。https://a.com/callback#token=ACCESS_TOKN

应用直接在前端链接中拿到令牌

注意这里使用了url的锚点而不是query参数,这是因为OAuth2.0允许跳转网址是http协议的,这样就存在中间人攻击的风险,而浏览器跳转时,锚点是不会发送到服务器的,所以可以减少风险

pasasword

直接使用用户在github上的用户名和密码去拿token

https://github.com/oauth2/token?grant_type=password&username=xxx&password=xx&client_id=clinet_id。此种授权方式不需要跳转,github直接把token放在json数据中作为响应。

client credentials

适用于命令行应用。A应用直接在命令行中请求github。

https://github.com/oatuh2.0/token?grant_type=clienet_credntials&client_id=client_id&client_scret=client_secret

这种方式给的令牌,是针对第三方应用的。即可能多个用户共用一个令牌

令牌的使用方式

在请求header中加上Authorization字段:如下

curl -H “Authorization: Bearer ACCESS_TOKEN” https://api.github.com

OAuth2.0允许用户自动更新令牌,再向第三方应用颁发令牌时,一次性颁发两个,一个用于获取数据,一个用于刷新令牌。令牌到期后,用户可以使用refresh_token发一个请求,格式如下

https://github.com./oauth2.0/token?grant_type=refresh_token&client_id=client_id&client_secret=client_secret&refresh_token=refresh_token

github校验通过后,会颁发新的令牌


以上是关于彻底搞明白OAuth2.0的主要内容,如果未能解决你的问题,请参考以下文章

彻底搞明白this

彻底搞明白Spring中的自动装配和Autowired

彻底搞明白JDK的Future机制

让你彻底搞明白项目中如何接入读写分离

彻底搞明白大数据量下Mysql的分页优化

彻底搞明白JDK 1.8 Lambda 表达式