当前位置: www.89677.com > 互联网 > 正文

OAuth2与OpenID区别和联系,通往Gmail账号的一扇隐形

时间:2019-11-17 04:34来源:互联网
现在的网民们经常遇到这种情况:某天你点开了一个有趣新奇的网站,比如Unroll.me,这个网站为Gmail用户提供方便快捷的邮件筛选和订阅服务,前提是你将自己的Gmail账户开放授权给他们

现在的网民们经常遇到这种情况:某天你点开了一个有趣新奇的网站,比如Unroll.me,这个网站为Gmail用户提供方便快捷的邮件筛选和订阅服务,前提是你将自己的Gmail账户开放授权给他们。

一、什么是OAuth2.0
官方网站:

原文地址:OAuth、OAuth2与OpenID区别和联系作者:杭州丁俊

 

等一等,你有没有想过自己到底是把访问私人邮箱的权利给了谁呢?Unroll.me这个新网站上没有任何企业认证信息,也没有企业邮箱账号、团队成员名录和隐私条款。根据经验,这个网站背后很有可能是一个不要脸的垃圾邮件传播者,或者是个喜欢寻开心的无聊人士,难道我们就这样把自己八年的邮件记录开放给他查看了么?收件箱中可能会有你各个网站的密码重置记录,你的银行账单以及各种私人信息,想想这些,真是不寒而栗。

权威定义:OAuth is An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications.

OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
        OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAuth是安全的。同时,任何第三方都可以使用OAuth认证服务,任何服务提供商都可以实现自身的OAuth认证服务,因而OAuth是开放的。

欢迎加入群:347245650   345531810 进行讨论相互交流  我的微信号:572839485**

幸亏Unroll.me并不是个黑心网站,网站的创始人和首席运营官佩里·布雷克·格曼已经保证会在网站正式进入公共测试之后添加所有的企业信息。

OAuth是一个开放协议,允许用户让第三方应用以安全且标准的方式获取该用户在某一网站、移动或桌面应用上存储的私密的资源(如用户个人信息、照片、视频、联系人列表),而无需将用户名和密码提供给第三方应用。

OAuth简史
2007年12月4日发布了OAuth Core 1.0, 此版本的协议存在严重的安全漏洞:OAuth Security Advisory: 2009.1,更详细的安全漏洞介绍可以参考:Explaining the OAuth Session Fixation Attack。
2009年6月24日发布了OAuth Core 1.0 Revision A:此版本的协议修复了前一版本的安全漏洞,并成为RFC5849,我们现在使用的OAuth版本多半都是以此版本为基础。
OAuth 2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0。 OAuth 2.0关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。

 

但是,自从2010年3月Gmail加入了开放授权(OAuth)协议之后,已经有无数新兴互联网站点在你的账号中开了一扇隐形的窗户,而且这个窗户还是永久开放的。也许这项协议给开发者和用户们都带来了极大的便利,但我们也不得不担心开放授权协议的隐私性隐患。

OAuth 2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0。 OAuth 2.0关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。

OAuth角色:

网页授权获取用户基本信息此接口是通过OAuth2.0来完成网页授权的,是安全可靠的。

通往开放授权之路

21世纪的第一个十年中,许多网络极客们都非常抵触“密码反模式“(The Password Anti-Pattern),这是一种之前被许多网络服务所采用的第三方授权协议,这种协议要求用户输入邮箱的账号与密码,将服务与邮箱账户进行连接,比如我们大家很熟悉的“从你的MSN联系人中寻找友邻”。虽然方便,但它毫无疑问也是钓鱼大杀器。

人们想到的解决办法就是“开放授权”(OAuth)协议,这种协议的授权不会使第三方接触到用户的账号信息,即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权。假如你曾经将你的微博、邮箱或人人账号授权给某项服务,那么你就是开放授权协议的使用者之一。

开放授权协议一次性解决了许多问题,比如用户的授权过程更为简单,只需点击几下就行,你的账号与密码也不会被有心人得到,服务开发者们也不用为了储存和传输大量的用户账号信息而烦恼。

但如此的便利也带来了另一个弊端:将用户变得越来越不在意自己的账号。即便是资深网民,也会无意识地让自己的账号跟无数第三方应用连接起来,比如俺的豆瓣账号,不经意间也授权给了十好几个应用,微博和人人更不用说,种类繁多的小游戏和“星座信息”之类的杂项服务无一例外都会要求你授权给他们。但是跟社交网站比起来,邮箱中所存有的重要信息明显更多,如果你的常用Gmail账号授权给了许多网站,那么很可能你的私人信息已经暴露的差不多了。

OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。

  • Consumer:消费方
  • Service Provider:服务提供者
  • User:用户

  一、什么是OAuth2.0

    OAuth是一个开放协议,允许用户让第三方应用以安全且标准的方式获取该用户在某一网站、移动或桌面应用上存储的私密的资源(如用户个人信息、照片、视频、联系人列表),而无需将用户名和密码提供给第三方应用。

OAuth 2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0。 OAuth 2.0关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。

    OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。(来自于网络)

 

  二、微信公众平台OAuth2.0授权详细步骤

OAuth2与OpenID区别和联系,通往Gmail账号的一扇隐形窗。     1. 用户关注微信公众账号。
           2. 微信公众账号提供用户请求授权页面URL。
           3. 用户点击授权页面URL,将向服务器发起请求
           4. 服务器询问用户是否同意授权给微信公众账号(scope为snsapi_base时无此步骤)
           5. 用户同意(scope为snsapi_base时无此步骤,不弹出授权页面,直接跳转,只能获取用户openid)
           6. 服务器将code参数通过回调传给微信公众账号

           7. 微信公众账号获得code参数
           8. 微信公众账号通过code参数向服务器请求Access Token
           9. 服务器返回Access Token和OpenID给微信公众账号
          10. 微信公众账号通过Access Token向服务器请求用户信息(scope为snsapi_base时无此步骤)
          11. 服务器将用户信息回送给微信公众账号(scope为snsapi_base时无此步骤)

      三、配置授权回调页面域名

         www.89677.com 1

点击右边的修改 

www.89677.com 2

 

填写授权页面需要注意:

www.89677.com 3

这里我们填写自己的域名www.wechat68.com

www.89677.com 4

 

www.89677.com 5   

这样我的授权页面的域名配置成功了

 

   四、用户授权并获取code  www.89677.com,使用code换取access_token **使用access_token获取用户信息  Java代码如下
授权访问的URL:


**       **

www.89677.com 6www.89677.com 7

package com.javen.course.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONObject;

import com.javen.course.entity.UserInfo_weixin;
import com.javen.course.util.HttpUtil;
/**
 * 
 * @author 简爱微萌
 * @Email zyw205@gmail.com
 * 接口权限中设置OAuth2.0网页授权 域名 如:www.wechat68.com
 * 授权访问的URL:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx614c453e0d1dcd12&redirect_uri=http://www.wechat68.com/Javen/OauthTest&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect
 */
public class Oauth2Servlet extends HttpServlet {
private String get_access_token_url="https://api.weixin.qq.com/sns/oauth2/access_token?" +
        "appid=APPID" +
        "&secret=SECRET&" +
        "code=CODE&grant_type=authorization_code";
private String get_userinfo="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

    private static final long serialVersionUID = -644518508267758016L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 将请求、响应的编码均设置为UTF-8(防止中文乱码)  
        request.setCharacterEncoding("UTF-8");  
        response.setCharacterEncoding("UTF-8"); 
        String code=request.getParameter("code");

        get_access_token_url=get_access_token_url.replace("APPID", "wx614c453e0d1dcd12");
        get_access_token_url=get_access_token_url.replace("SECRET", "fd00642f7a2fea32c5a7b060d9c37db1");
        get_access_token_url=get_access_token_url.replace("CODE", code);

        String json=HttpUtil.getUrl(get_access_token_url);


        JSONObject jsonObject=JSONObject.fromObject(json);
        String access_token=jsonObject.getString("access_token");
        String openid=jsonObject.getString("openid");

        get_userinfo=get_userinfo.replace("ACCESS_TOKEN", access_token);
        get_userinfo=get_userinfo.replace("OPENID", openid);

        String userInfoJson=HttpUtil.getUrl(get_userinfo);

        JSONObject userInfoJO=JSONObject.fromObject(userInfoJson);

        String user_openid=userInfoJO.getString("openid");
        String user_nickname=userInfoJO.getString("nickname");
        String user_sex=userInfoJO.getString("sex");
        String user_province=userInfoJO.getString("province");
        String user_city=userInfoJO.getString("city");
        String user_country=userInfoJO.getString("country");
        String user_headimgurl=userInfoJO.getString("headimgurl");

    //    UserInfo_weixin userInfo=new UserInfo_weixin(user_openid, user_nickname, user_sex, user_province, user_city, user_country, user_headimgurl);
        response.setContentType("text/html; charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
        out.println("  <BODY>");
        out.print("    This is ");
        out.print(this.getClass());
        out.println(", using the POST method n");
        out.println("openid:"+user_openid+"nn");        
        out.println("nickname:"+user_nickname+"nn");        
        out.println("sex:"+user_sex+"nn");        
        out.println("province:"+user_province+"nn");        
        out.println("city:"+user_city+"nn");        
        out.println("country:"+user_country+"nn");
        out.println("<img src=/"+user_headimgurl+"/");
        out.println(">");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
        out.println("  <BODY>");
        out.print("    This is ");
        out.print(this.getClass());
        out.println(", using the POST method");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }


}

微信授权代码

 

 

 

www.89677.com 8www.89677.com 9

public static String getUrl(String url){
        String result = null;
        try {
            // 根据地址获取请求
            HttpGet request = new HttpGet(url);
            // 获取当前客户端对象
            HttpClient httpClient = new DefaultHttpClient();
            // 通过请求对象获取响应对象
            HttpResponse response = httpClient.execute(request);

            // 判断网络连接状态码是否正常(0--200都数正常)
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                result= EntityUtils.toString(response.getEntity());
            } 
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }

getUrl

www.89677.com 10www.89677.com 11

/**
     * 发起https请求并获取结果
     * 
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr 提交的数据
     * 
     */
    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyTrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            log.error("Weixin server connection timed out.");
        } catch (Exception e) {
            log.error("https request error:{}", e);
        }
        return null;
    }

Https请求

www.89677.com 12www.89677.com 13

package com.javen.weixin.util;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
 * 证书信任管理器(用于https请求)
 */
public class MyTrustManager implements X509TrustManager {

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

证书信任管理器

 

 

       如果对你有帮助请我喝杯咖啡 左微信 右支付宝 个人微信公众号javenlife

 

www.89677.com 14www.89677.com 15 www.89677.com 16

隐私危机

现在我们可以列出一长串需要Gmail第三方授权的应用,功能五花八门:整理邮件、邮件备份、邮件共享等等等等。一旦授权成功,所有的这些应用都会拥有对你邮箱的无限制查看权,这也正是危险之处。也许你相信谷歌能保证你的邮件安全,但是你是否相信三个大学生用三个月写的小程序?或者一个程序员用业余时间编出来的游戏之作?要是这些应用的开发者中有一个心怀不轨,那就大事不妙了。一旦这些应用的授权用户名单被窃取或泄漏,那么所有曾经使用过它们的用户的Gmail全部内容都会暴露。更可怕的是,如果应用开发方没有发现用户信息泄漏,或者隐瞒不报,那么你永远也不会知道自己的邮件历史已经被有心人得到了。

新浪微博API目前也使用OAuth 2.0。

OAuth流程

如何应对

很显然,我们不能因噎废食,因为这样的小隐患就废除开放授权协议这样的优秀产品。为了保证我们的个人隐私安全,大家可以这样做:

清理你的第三方应用授权: 现在,马上登陆你的各种常用账号,将那些无关紧要的或你不再使用的第三方应用取消授权,特别是那些拥有Gmail授权的应用。你可以利用这个网站MyPermissions.org来获取自己的授权应用名单。

授权之前要三思: 在你将自己的账号授权给一个应用之前,先查清楚应用开发者的具体信息和他们的隐私保护条款,知道自己到底授权给了谁。一旦你觉得有不对劲的地方,马上点屏幕右上角。

当你怀疑时,马上改密码: 当你觉得自己的邮件有可能被其他人阅读了,或是自己的账号被别人所登陆了,但又不确定是哪次授权引来的狼,那就马上重设你的密码吧。

本文编译自 wired

原文:

  • 用户访问客户端的网站,想操作用户存放在服务提供方的资源。
  • 客户端访问服务提供方的临时令牌页面申请一个临时令牌。
  • 服务提供方验证客户端的身份后,授予一个临时令牌。
  • 客户端获得临时令牌后,将用户引导至服务提供方的授权页面请求用户授权。在这个过程中将临时令牌和客户端的回调连接发送给服务提供方。
  • 用户在服务提供方的网页上输入用户名和密码,然后授权该客户端访问所请求的资源。
  • 授权成功后,服务提供方引导用户返回客户端的网页。
  • 客户端根据临时令牌访问服务提供方的访问令牌页面 获取访问令牌。
  • 服务提供方根据临时令牌和用户的授权情况授予客户端访问令牌。
  • 客户端使用获取的访问令牌访问存放在服务提供方上的受保护的资源。

二、微信公众平台OAuth2.0授权

www.89677.com 17

微信公众平台OAuth2.0授权详细步骤如下:

有腿的OAuth
        我们前面描述的OAuth,被称为三条腿的OAuth(3-Legged OAuth),这也是OAuth的标准版本。这里所谓的“三条腿”,指的是授权过程中涉及前面提到的三种角色,也就是:消费方,服务提供者,用户。不过有 些情况下,不需要用户的参与,此时就产生了一个变体,被称作两条腿的OAuth(2-Legged OAuth),一般来说,访问私有数据的应用需要三条腿的OAuth,访问公共数据的应用需要两条腿的OAuth。
         两条腿的OAuth和三条腿的OAuth相比,因为没有用户的参与,所以在流程中就不会涉及用户授权的环节,也就不需要使用Token,而主要是 通 过Consumer Key和Consumer Secret来完成签名的,此时的Consumer Key和Consumer Secret基本等价于账号和密码的作用。

  1. 用户关注微信公众账号。
  2. 微信公众账号提供用户请求授权页面URL。
  3. 用户点击授权页面URL,将向服务器发起请求
    4. 服务器询问用户是否同意授权给微信公众账号(scope为snsapi_base时无此步骤)
  4. 用户同意(scope为snsapi_base时无此步骤)
  5. 服务器将CODE通过回调传给微信公众账号
  6. 微信公众账号获得CODE
  7. 微信公众账号通过CODE向服务器请求Access Token
  8. 服务器返回Access Token和OpenID给微信公众账号
  9. 微信公众账号通过Access Token向服务器请求用户信息(scope为snsapi_base时无此步骤)
  10. 服务器将用户信息回送给微信公众账号(scope为snsapi_base时无此步骤)

OAuth和OpenID的区别
OAuth关注的是authorization授权,即:“用户能做什么”;
 而OpenID侧重的是authentication认证,即:“用户是谁”。
OpenID、OAuth联合使用例子:

 

  • OpenID 用户希望访问其在example.com的账户
  • example.com(在OpenID的黑话里面被称为“Relying Party”) 提示用户输入他/她/它的OpenID
  • 用户给出了他的OpenID,比如说""
  • example.com 跳转到了用户的OpenID提供商“mypopenid.com”
  • 用户在"myopenid.com"(OpenID provider)提示的界面上输入用户名密码登录
  • “myopenid.com" (OpenID provider) 问用户是否要登录到example.com
  • 用户同意后,"myopenid.com" (OpenID provider) 跳转回example.com
  • example.com 允许用户访问其帐号
  • 用户在使用example.com时希望从mycontacts.com导入他的联系人
  • example.com (在OAuth的黑话里面叫“Consumer”)把用户送往mycontacts.com (黑话是“Service Provider”)
  • 用户在mycontacts.com 登录(可能也可能不用了他的OpenID)
  • mycontacts.com问用户是不是希望授权example.com访问他在mycontact.com的联系人
  • 用户确定
  • mycontacts.com 把用户送回example.com
  • example.com 从mycontacts.com拿到联系人
  • example.com 告诉用户导入成功

 

        上面的例子告诉我们,OpenID是用来认证协议,OAuth是授权协议,二者是互补的。OAuth来自Twitter,可以让A网站的用户共享B网站上的他自己的资源,而不需泄露用户名和密码给另外一个网站。OAuth可以把提供的Token,限制在一个网站特定时间段的的特定资源。

使用的AppId和AppSecret在功能-高级功能-开发模式-开发者凭据中,可以找到。www.89677.com 18

Google Connect(基于OpenID +  OAuth思想的定制)
www.89677.com 19

OAuth 2.0的新特性 - 6种全新流程:

  • User-Agent Flow – 客户端运行于用户代理内(典型如web浏览器)。
  • Web Server Flow – 客户端是web服务器程序的一部分,通过http request接入,这是OAuth 1.0提供的流程的简化版本。
  • Device Flow – 适用于客户端在受限设备上执行操作,但是终端用户单独接入另一台电脑或者设备的浏览器
  • Username and Password Flow – 这个流程的应用场景是,用户信任客户端处理身份凭据,但是仍然不希望客户端储存他们的用户名和密码,这个流程仅在用户高度信任客户端时才适用。
  • Client Credentials Flow – 客户端使用它的身份凭据去获取access token,这个流程支持2-legged OAuth的场景。
  • Assertion Flow – 客户端用assertion去换取access token,比如SAML assertion。

OAuth 2.0的新特性:
        持信人token - OAuth 2.0 提供一种无需加密的认证方式,此方式是基于现存的cookie验证架构,token本身将自己作为secret,通过HTTPS发送,从而替换了通过 HMAC和token secret加密并发送的方式,这将允许使用cURL发起APIcall和其他简单的脚本工具而不需遵循原先的request方式并进行签名。
        签名简化 - 对于签名的支持,签名机制大大简化,不需要特殊的解析处理,编码,和对参数进行排序。使用一个secret替代原先的两个secret。
        短期token和长效的身份凭据 - 原先的OAuth,会发行一个有效期非常长的token(典型的是一年有效期或者无有效期限制),在OAuth 2.0中,server将发行一个短有效期的access token和长生命期的refresh token。这将允许客户端无需用户再次操作而获取一个新的access token,并且也限制了access token的有效期。
        角色分开 - OAuth 2.0将分为两个角色: Authorization server负责获取用户的授权并且发布token; Resource负责处理API calls。

编辑:互联网 本文来源:OAuth2与OpenID区别和联系,通往Gmail账号的一扇隐形

关键词: