OAuth2的学习,我也是从阮一峰老师的博客中开始的:
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
下文中以“该博客”指代阮老师的博客。
但,阮一峰老师的博客似乎忽略了很多细节。
OAuth2的实际应用中,最常见的就是“授权码模式”了。
微博是这种模式,微信也是这种模式。
总结来说,就是简单的二步:
1.获取code
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了),网站允许用户以微博账号登录,且需要读取用户的微博信息(账号、评论等等)。
显然,这过程中需要用户授权。
第一步:
https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
第二步:
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传到我们网站来。
回到第二个问题。
该博客下有人是这样回答的:
为什么授权码模式需要这个授权码 当然是为了安全性 首先在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的
获得了access_token之后 向RS发起请求 RS其实会与AS交互 来校验access_token 所以你想直接伪造一个access_token 那也是不ok的
突然想到漏说了一块 关于为什么不直接用HTTPS重定向回client
是因为不是所有client server都支持HTTPS~所以为了通用性 和安全性 才衍生出来这么一个Auth code
但是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当中#号后面的那一部分。
博客中的示例:
HTTP/1.1 302 Found
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/
都讲得比较详细。
分享到:
相关推荐
yii2-oauth2-server, 用于实现OAuth2服务器的包装器( https yii2-oauth2-server用于实现OAuth2服务器的包装器( https://github.com/bshaffer/oauth2-server-php 插件)安装安装这里扩展的首选方法是通过 Composer 。...
springboot和apache的开源项目org.apache.oltu.oauth2组合搭建的oauth2环境,一般的oauth配置下就可以用了,但是我这个项目,是用原理上讲如何搭建oauth2,哪个controller转发到哪个controller,为什么这样,都有...
赠送jar包:spring-security-oauth2-2.3.5.RELEASE.jar; 赠送原API文档:spring-security-oauth2-2.3.5.RELEASE-javadoc.jar; 赠送源代码:spring-security-oauth2-2.3.5.RELEASE-sources.jar; 赠送Maven依赖信息...
#OAuth2-Defender ##主要技术 Maven Spring Boot Spring Security Spring Security OAuth2.0 MySQL ##修改数据库配置 修改defender-oauth2-authorization\src\main\resources\...
oauth2oauth2oauth2
模拟OAuth2 单点登录的java代码实现。模拟OAuth2 单点登录的java代码实现。模拟OAuth2 单点登录的java代码实现。模拟OAuth2 单点登录的java代码实现。
还在烦恼OAuth2技术只依赖boot吗?我提供了纯java技术实现OAuth2的全部实现,含客户端和服务端的完整解决方案。
使用spring oauth2框架做授权鉴定。想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的。 spring security可以通过SecurityContextHolder.getContext().getAuthentication()....
spring security oauth2的源码,方便研究,备份一下。
OAuth 2 0 is the next evolution of the OAuth protocol which was originally created in late 2006 OAuth 2 0 focuses on client developer simplicity while providing specific authorization flows for web a
springboot整合Oauth2,GateWay实现网关登录授权验证
描述了oauth2的原理(不含代码,如需demo请联系3546766954@qq.com),简单介绍了oauth2四种验证方式
包含 1.Getting Started with OAuth 2.0.pdf 2.Mastering OAuth 2.0.pdf 3.Oauth2 in Action.pdf 4.OAuth2.0 Cookbook.pdf
about sping secutity oauth2
passport-oauth2, 用于 Passport 和 node.js的OAuth 2.0认证策略 passport-oauth2 通用 OAuth 2.0认证策略用于 Passport 。这个模块允许你在 node.js 应用程序中使用 OAuth 2.0进行身份验证。 通过插入 Passport,...
javascript-oauth2, 在使用CORS的JavaScript中,实现 OAuth2 javascript-oauth2OAuth2客户端在纯JavaScript中的实现,在 3-clause BSD许可协议下的许可证。概述为 window.oauth2 对象提供一个包含实现OAuth2-...
一个springboot为框架的security oauth2应用例子,同时集成了swagger2的 restful API查看页面,druid数据源监控, mybatis自动生成和分页插件,远程资源服务器的认证和授权,也可以去github下载 ...
oauth2-server, 一个 PHP OAuth 2.0服务器实现 PHP OAuth服务器一个 PHP OAuth 2.0服务器实现。 安装包可以以用 Composer 安装,也可以以通过直接修改 composer.json 或者使用 composer require 命令来安装。co
Oauth2 Java demo
部署了一套非常全的OAuth2.0的例子 其中包括客户端和服务器端,专门为了OAuth2.0初学者提供了一个学习的资料 可以参考微博地址:http://blog.csdn.net/jbjwpzyl3611421/article/details/51130030