03-oauth2

作者: 16325 | 来源:发表于2020-06-08 17:12 被阅读0次

    oauth2

    OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。

    应用场景

    第三方应用授权登录:在APP或者网页接入一些第三方应用时,时长会需要用户登录另一个合作平台,比如QQ,微博,微信的授权登录。


    image.png

    原生app授权:app登录请求后台接口,为了安全认证,所有请求都带token信息,如果登录验证、请求后台数据。

    前后端分离单页面应用(spa):前后端分离框架,前端请求后台数据,需要进行oauth2安全认证,比如使用vue、react后者h5开发的app。

    流程

    (A)用户打开客户端以后,客户端要求用户给予授权。
    (B)用户同意给予客户端授权。
    (C)客户端使用上一步获得的授权,向认证服务器申请令牌。
    (D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
    (E)客户端使用令牌,向资源服务器申请获取资源。
    (F)资源服务器确认令牌无误,同意向客户端开放资
    源。

    授权模式

    • 授权码模式(authorization code)
    • 简化模式(implicit)
    • 密码模式(resource owner password credentials)
    • 客户端模式(client credentials)

    下面详细解释:

    授权码模式

    • A是我们的应用,B是oauth的服务端(可能是qq,github,也可以自己实现一个类似cas服务端的服务进程)
    • 用户未认证,需要认证,那么A引导用户去B的网页,请求:

    https://b.com/oauth/authorize?
    response_type=code&
    client_id=CLIENT_ID&
    redirect_uri=CALLBACK_URL&
    scope=read

    response_type=说明是授权码模式
    client_id=CLIENT_ID是A事先在B网站注册的客户端id
    redirect_uri=CALLBACK_URL是A的回调地址
    scope=read说明请求范围是只读的

    • 用户跳转后,B 网站会要求用户登录,然后询问是否同意给予 A 网站授权。用户表示同意,这时 B 网站就会跳回redirect_uri参数指定的网址。跳转时,会传回一个授权码,就像下面这样

    https://a.com/callback?code=AUTHORIZATION_CODE
    上面 URL 中,code参数就是授权码。

    • A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。注意这里是后端请求,不经用用户浏览器,保证安全

    https://b.com/oauth/token?
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET&
    grant_type=authorization_code&
    code=AUTHORIZATION_CODE&
    redirect_uri=CALLBACK_URL

    client_id=CLIENT_ID事先注册的客户端id
    client_secret=CLIENT_SECRET 这个,就是后端保存的客户端的密钥
    grant_type=authorization_code 授权码模式
    code=AUTHORIZATION_CODE 刚刚得到的授权码
    redirect_uri=CALLBACK_URL 回调地址

    • B 网站收到请求以后,就会颁发令牌。具体做法是向redirect_uri指定的网址,发送一段 JSON 数据

    {
    "access_token":"ACCESS_TOKEN",
    "token_type":"bearer",
    "expires_in":2592000,
    "refresh_token":"REFRESH_TOKEN",
    "scope":"read",
    "uid":100101,
    "info":{...}
    }
    上面 JSON 数据中,access_token字段就是令牌,A 网站在后端拿到了

    简化模式(implicit)

    • 有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)"隐藏式"(implicit)
    • 第一版,A网站引导用户去B网站登录

    https://b.com/oauth/authorize?
    response_type=token&
    client_id=CLIENT_ID&
    redirect_uri=CALLBACK_URL&
    scope=read

    response_type=token表示直接使用token,不用授权码
    其他字段与授权码方式相同

    • 用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站

    https://a.com/callback#token=ACCESS_TOKEN

    • 上面 URL 中,token参数就是令牌,A 网站因此直接在前端拿到令牌。

    注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。

    这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。

    密码模式

    • 如果B高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

    • A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌

    https://oauth.b.com/token?
    grant_type=password&
    username=USERNAME&
    password=PASSWORD&
    client_id=CLIENT_ID
    上面 URL 中,grant_type参数是授权方式,这里的password表示"密码式",username和password是 B 的用户名和密码。

    • 第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。

    客户端模式

    • 最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。
    • 第一步,A 应用在命令行向 B 发出请求。

    https://oauth.b.com/token?
    grant_type=client_credentials&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET

    上面 URL 中,grant_type参数等于client_credentials表示采用凭证式,client_id和client_secret用来让 B 确认 A 的身份。

    • 第二步,B 网站验证通过以后,直接返回令牌。
      注意: 这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。

    令牌的使用

    • A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。此时,每个发到 API 的请求,都必须带有令牌。具体做法是在请求的头信息,加上一个Authorization字段,令牌就放在这个字段里面。
    curl -H "Authorization: Bearer ACCESS_TOKEN" \
    "https://api.b.com"
    

    更新令牌

    令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 2.0 允许用户自动更新令牌。

    • 具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。

    https://b.com/oauth/token?
    grant_type=refresh_token&
    client_id=CLIENT_ID&
    client_secret=CLIENT_SECRET&
    refresh_token=REFRESH_TOKEN

    上面 URL 中,grant_type参数为refresh_token表示要求更新令牌,client_id参数和client_secret参数用于确认身份,refresh_token参数就是用于更新令牌的令牌。

    • B 网站验证通过以后,就会颁发新的令牌。

    总结

    综上所述,A就是app或者vue,B就是我们的后台,可以拆分出认证服务器和资源服务器,分别用来鉴权和资源访问。 资源服务器发现token失效,那么需要去认证服务器认证,token保存在比如redis里,资源服务器和认证服务器都能访问。

    相关文章

      网友评论

          本文标题:03-oauth2

          本文链接:https://www.haomeiwen.com/subject/zwnvzhtx.html