`
erichi101
  • 浏览: 10085 次
文章分类
社区版块
存档分类
最新评论

OAuth2 授权码模式为什么不直接返回access_token

阅读更多

 

OAuth2的学习,我也是从阮一峰老师的博客中开始的:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 
下文中以“该博客”指代阮老师的博客。 

但,阮一峰老师的博客似乎忽略了很多细节。 

OAuth2的实际应用中,最常见的就是“授权码模式”了。 
微博是这种模式,微信也是这种模式。 
总结来说,就是简单的二步: 

Java代码  收藏代码
  1. 1.获取code  
  2. 2.根据code,去获取access_token  




以微博为例(http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E):

假设我们开发一个网站(称为client;相对应的,微博就是server了),网站允许用户以微博账号登录,且需要读取用户的微博信息(账号、评论等等)。 
显然,这过程中需要用户授权。 

第一步: 

Java代码  收藏代码
  1. https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI  


第二步: 

Java代码  收藏代码
  1. https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE  



这其中有几个问题: 
1.获取code时,传递的二个变量(clent_id,redirect_url),没有一个是跟用户有关的,那微博怎么知道我们请求的是哪个用户的授权呢? 
这个问题现在看来很可笑,但刚开始确实是蒙圈了。 
其实,在第一步的URI发出后,是要求用户跳转到server端登录的。这很好理解,如果用户不登录,那你怎么知道是哪个用户呢,他又怎么给你授权呢? 
此外,可以看到,第一步的URI,放在我们网站页面的任何位置都可以;它也不要求传递跟session相关的任何信息。 
这个URI对应的页面是微博开发的,跟我们网站没关系。 
事实上,这个URI可以直接拷贝到浏览器里发起请求;这个时候,是浏览器跟微博的一个交互,我们的网站是一无所知的。 
那什么时候我们得知用户给我们授权了呢? 
第一步URI的请求,浏览器得到的是一个http的重定向响应,这个重定向指向的就是我们的网站;此时浏览器向我们的网站发起请求: 
类似于: 
https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz 
站在我们网站后台程序的角度来看,我们是“忽然”(在此这前,它一无所知)收到一个code了,而这个code,是跟微博的一个用户一一对应的,我们拿这个code向微博发起请求,就能获得用户的授权,获得access_token,再发起另一请求,就可以获取用户信息了。 

2.为什么在第一个URI请求发出后,微博的302重定向响应中,没有直接返回access_token,而是只返回一个code呢? 
其实最初我的疑问更可笑:我想,为什么微博不直接返回access_token给我们网站呢? 
这个问题的答案是,发起第一步的URI请求的,是浏览器!还记得前面我说的“我们的网站是一无所知”吗?此时微博是与浏览器在通信,而不是我们的网站,当然不能把参数传返回到我们网站了。 
微博只能通过返回一个302响应,让浏览器重新向我们网站发起请求,把code传到我们网站来。 

回到第二个问题。 
该博客下有人是这样回答的: 

Java代码  收藏代码
  1. 为什么授权码模式需要这个授权码 当然是为了安全性 首先在OAuth体系中access_token是作为访问获取资源的唯一凭据 如果在AS授权完成之后 直接通过重定向传回access_token 那么HTTP 302不是安全的 Attacker有可能会获取到access_token 但是如果只返回Authorization code 就算别人获得了也没什么卵用 因为Authorization code不能获取到资源 在client向AS请求access_token的过程中 是通过HTTPS来保证安全的 而且获得access_token是需要client secret与Authorization code一起的 Attacker知道了Authorization code但并不知道client secret 同样也不能获得到access_token 所以client与AS是有责任保护好client secret的  
  2. 获得了access_token之后 向RS发起请求 RS其实会与AS交互 来校验access_token 所以你想直接伪造一个access_token 那也是不ok的  
  3.   
  4.   
  5. 突然想到漏说了一块 关于为什么不直接用HTTPS重定向回client  
  6. 是因为不是所有client server都支持HTTPS~所以为了通用性 和安全性 才衍生出来这么一个Auth code  
  7. 但是AS肯定是实现HTTPS的 所以在client向AS提起request 是木有问题的~  



我自己的理解,是这样的: 
直接返回access_token有可能被黑客拦截到,而拿到access_token就可以获得用户信息了,非常不安全。 
那最容易想到的是,微博通过https返回access_token啊,https会对access_token加密,那不就可以了吗? 
为什么这个方法不可行呢? 
因为有可能我们的网站不支持https!站在微博的角度来看,千千万万的第三方网站,你要求每个网站都支持https,是不太现实的。 
stackoverflow上的一个回答(http://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works-s)说这是“一个巨大的痛苦”:“a huge pain”。 

那为什么返回code再去获取access_token就安全了呢? 
因为这时候再去获取access_token,就是https请求了,发起方为我们的网站,接收方为微博,而微博作为OAuth server,肯定提供https。 
但是,另一个问题来了,黑客拿到了code,它也向微博发起请求去获取access_token是不是就可以了呢? 
也是不可以的。 
因为向微博请求access_token时,还要带上我们网站的“密码”(client secret)。 
这个密码,是我们网站在微博开放平台上注册时获得的(同时会得到一个client_id,这个值在第一步的URI里用到了)。 
这一点在该博客没有提出来,最容易让人困惑。 

3.为什么简化模式(implicit grant type)是可行的? 
这个在stackoverflow有回答,前面也提到过: 
http://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works-s 

这就涉及到一个知识点: 
浏览器不会把URL当中的“hash fragment”发给服务器。hash fragment是只留在浏览器的地址栏的,它可以被网页的js读取到:window.location.hash。 
既然hash fragment没有发给服务器,那即使黑客拦截到请求,也获取不到它。 
什么是hash fragment?就是URL当中#号后面的那一部分。 
博客中的示例: 

Java代码  收藏代码
  1. HTTP/1.1 302 Found  
  2. Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600  



可以得知,“#access_token=2YotnFZFEjr1zCsicMWpAA”这一部分是留在浏览器这边的。 
当浏览器接收到到该响应时,向http://example.com/cb发起请求,而后者的响应页面当中,应当有读取hash fragment的代码。 
这样,client就拿到了access_token了。 

解决了这三个问题,我本想到实际场景中抓包看看的,但遗憾的是,不管是蘑菇街还是聚美优品,这些允许以微博账号登录的网站,都只看到获取code那一步,没有看到获取access_token那一步。 
或许改天有空可以自己在微博开放平台上注册一个应用来验证一下。 
不过网上有人验证过微博的: 
https://segmentfault.com/a/1190000000666685 

此外还有一些关于微信OAuth2的实际例子: 
http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html 
http://zeusjava.com/2015/04/22/wechat-get-userinfo/ 
都讲得比较详细。 

 

zz:https://bylijinnan.iteye.com/blog/2277548

 

分享到:
评论

相关推荐

    OAuth2获取token报错invalid stream header

    在整合springcloud gateway、eureka、security、OAuth2的时候,采用授权码模式,用授权码去访问/oauth/token获取token时,遇到invalid stream header异常。 解决方法: 检查需要创建的OAuth2的几张表:oauth_access_...

    oauth2-client-demo:野兽派OAuth2客户端演示

    测试OAuth2授权码授予过程 没有js的js代码很少。 运行演示 如果您不想使用sws,则可以使用python 3。 python server . py 实用程序脚本 修改scripts/get_refresh_token以从CTR API检索刷新/访问令牌。 ./scripts...

    hope-oauth:最精简的oauth2授权认证服务:认证服务,资源服务,授权码模式,数据库持久化令牌,客户端

    授权码模式(即先登录凭证,再获取令牌)[最常用] 密码 密码模式(将用户名,密码传过去,直接获取令牌) client_credentials 客户端模式(无用户,用户向客户端注册,然后客户端以自己的名义向'服务端'获取资源)...

    oauth-jsclient:Intuit的NodeJS OAuth客户端提供了一组方法,可以更轻松地使用OAuth2.0和Open ID

    授权码流程 步骤1 适用范围: 第2步 样本 帮手 AccessToken有效吗 刷新access_token 通过显式传递refresh_token刷新access_token 撤消access_token 令牌的获取器/设置器 检索令牌: 设置令牌: 将OAuth1.0...

    微信扫码登录.php

    第一步是显示二维码,这各有两种方式,一种是打开一个新页面显示二维码可以通过构建类似 ...用户扫码允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数,这是要通过code获取access_token,url格式...

    oauth2:原型 Spring-security-oauth2

    获取授权码 交换授权码来获得访问令牌 授权请求 方式2:基于客户端 返回的数据 {"access_token":"3420d0e0-ed77-45e1-8370-2b55af0a62e8","token_type":"bearer","refresh_token":"b36f4978-a172-4aa8-af89-60f58abe3...

    springboot-adminlte-oauth2-sso:演示Spring-boot + Admin LTE + Oauth2 Sso

    发布Postgres 冬眠胸腺管理员LTE 2.3.3授权码流程UI->授权UI(授权)->资源资源所有者密码凭证流获取访问令牌$ curl -XPOST -u news:news_secret localhost:9999/auth/oauth/token -d grant_type=password -d ...

    demo-oauth2-spring-security:带有Spring Security OAuth 2的简单密码流演示

    demo-oauth2-spring-security 一个带有Spring Security OAuth 2的简单密码流演示 测验 您可以使用进行测试。 首先,您需要获取access_token 为该地址创建POST请求: 您也必须通过基本身份验证,这是客户端凭据,...

    阿里巴巴API开发sdk .net平台

    ini.WriteValue("Setting", "access_token", hs["access_token"].ToString()); ini.WriteValue("Setting", "datatime", System.DateTime.Now.ToString()); strAccToken = hs["access_token"].ToString(); } ...

    MCloud - OAuth2 认证中心

    当我们授权之后,就可以得到 **access_token**,此时选中并点击 Use Token,然后我们再次访问之前无权限的 API ![qq 20171022013209]...

    Jetty人人开放平台Token

    步骤: 1. 解压并导入myeclipse; 2. 修改renren.html:搜索name=...5. 修改相应的API_KEY和SECRET_KEY,最后的CODE修改为step3获取到的CODE,然后运行就会返回一个json格式的字符串,里面就有你想要的access token

    RestLogin:简单的 Rest Oauth2 登录

    休息登录使用 BCrypt 密码编码的 Simple Rest Oauth2 登录获取 access_token: URL: 获取 refresh_token: URL: 访问资源(只允许角色'manager'):URL: HEADER 授权:bearer YOUR_ACCESS_TOKEN 对于所有人: URL: ...

    python-asana:Asana API v1的官方Python客户端库

    验证个人访问令牌使用您的Asana个人访问令牌创建客户端: client = asana.Client.access_token('PERSONAL_ACCESS_TOKEN')OAuth 2 嘉尚支持的OAuth 2. asana处理一些对你的OAuth流程的详细情况。 使用您的OAuth客户端...

    spa_oauth_proxy:单页应用程序 OAuth v2 代理

    单页应用程序 OAuth 代理 ... 它充当授权服务器的客户端。 应用程序只看到一个加密的令牌,需要将它作为标头发送回代理。 代理支持以下端点: ... $ ./spa_oauth_proxy -access-token-url="https://example.com/a

    jpsite-security-oauth2-open:微服务开放API授权平台

    本演示项目包括功能有新用户用户注册自动分配角色权限用户只能访问自己所拥有的角色权限访问路径开放平台用户可以申请获取客户ID和客户密钥用户可以通过客户ID获取授权码用户可以通过客户ID和密钥以及授权码获取...

    cas_wx:微信认证和CAS整合

    上述snsapi_base模式是静默模式,不需微信用户手动授权,用户感受不到界面的跳转,但仅可获取用户的openid信息,对于我们来说openid暂时足够了。 第二步:通过code换取网页授权access_token 获取code后,请求以下...

    ember-simple-auth-oauth2

    这是Ember Simple Auth库的扩展,该库提供了与OAuth 2.0兼容的身份验证器和授权者。 在Ember.js应用程序和OAuth 2.0服务器之间交换用户的凭据以及令牌时,您必须确保该连接使用HTTPS! 认证者 身份验证器(请参阅...

    OAuth协议 介绍

     OAuth不强求一个特定的用户接口或操作模式,也不限定服务提供方如何验证用户,特别适合认证证书对消费方不可用的情况,例如OpenID。 OAuth致力于为托管web服务认证提供统一的体验和实现,形成一个社区驱动的协议...

    mastodon-api:Mastodon API的ruby接口

    Mastodon APIRuby宝石 API的Ruby接口。 安装 gem 'mastodon-api', require: 'mastodon' 文献资料 所有文档都可以在上。 用法 假设您已经有给定Mastodon...然后,您可以在标准OAuth 2授权流程中使用客户端ID和密码。

    flickr-promoter

    FLICKR_PROMOTER_ACCESS_TOKEN Base64编码的OAuth凭证。如果未设置,将执行授权 如何使用 设置 使用https://gist.github.com/dzhus/0bf2a8b1990c288315411ce69bca56df作为回调URL,使用“ Web应用程序”应用程序...

Global site tag (gtag.js) - Google Analytics