原文链接: http://rsj217.diandian.com/post/2013-04-17/40050093587

本意是在注销账号前保留之前的一些数据。决定用python 爬取收藏。可是未登录无法爬取。想要登录有两种办法,伪造浏览器登录。第二就是注册新浪开发者账号,通过Oauth认证调用其API。

Oauth 的原理搞了一天才明白。很多网站都提供多语言的Oauth。而 1.0 和 2.0 的最大差别就是多了一个 callback 回调页面。关于这方面的说明很少,搞得我一头雾水折腾了好久。总算明白了。

Oauth的原理

现在多用 oauth2.0. 具体可以看其官方文档。用下面的图简单说明:

Consumer指应用程序,User是用户,Service是服务器。大致过程为,User使用程序Consumer。C 向 Service请求一个未授权的令牌(Request_token),这个时候 S 验证 C的合法性(通过开发者的 APP_KEY 和 APP_SECREST)。然后重定向到一个授权页面(通常由服务方提供)。此时用户进行授权,即输入用户名和密码,用户会自动向服务器发送 authorize request_token。得到授权的 request_token。再然后,授权通过后,跳转到一个 callback 页面。通过request_token用来向服务器请求,换取 acess_token。至此,认证结束。接下来要请求数据,只需要根据文档 把 acess_token 当参数传给服务器。

这样说比较抽象,举个简单的例子:

有一个人 U 想去银行 S 取钱。U 没事情去柜台,就委托朋友 C 去柜台。当C 去了银行S,给S说:我要帮 U 取钱。S 先验证 C 的身份,是合法公民。然后 S 打电话给 U。说:C 要帮你取钱,你确定么,确定的话就输入用户名和密码。 U 确定了。此时,S 就给了一个 钥匙给 C。说:我们不提供自动服务,给你钥匙,自己去库房取。然后 C 拿着钥匙,就去取钱了。取完之后给力 U。U 很感激。

通过上面的解释,应该可以知道整个过程中有三个URL请求地址,如下图:

这写地址由服务方提供,上面那个就是 qq 公共平台的url。新浪有新浪自己的。关于第一步,请求 request_token的时候,服务器也要认证开发者帐号,也就是银行认证 C 的合法身份。

每个 开发者都有app_key 和 app_secret.  app_key称为密钥, app_secret为密匙。开发者和服务都知道。然后 ,开发者通过  app_key 和 app_secret 通过 一种加密(sha1)得到一个字符串secretcode 公钥。再把 app_key 和 secretcode 发送给服务器。服务器接收之后,将发送到 app_key和服务器存储的 app_secret 通过同样的加密手段得到一个 secretcode2 和发送过来的secretcode进行对比,如果一样,则可以证明是通过。这一点好处是安全。不怕被抓包。

新浪 Oauth的运用

简单知道原理,就可以进行认证。

准备工作

需要向新浪申请开发者帐号,然后创建一个应用。之后会得到一个 app_key 和 app_secret。需要注意是一定要填写下面的回调地址:

新浪的是可以设置 本地的,例如 http://127.0.0.1/oauth/callback.php

豆瓣的需要公网可以访问的回调地址,不同api不一样。

布署

可以下载 官方提供的 SDK ,根据语言选择。这里选择 php。理由是 php的web环境可以一键安装。需要注意到是,新浪的 SDK需要 php 开启 curl。不然会报错。

文档结构如下:

config.php  开发者配置文件

index.php  登录主入口

callback.php 回调处理

saetv2.ex.class.php  SDK 主文件,提供认证和api调用

weibolist.php 认证成功之后的数据请求和展示

引用官方的 SDK ,根据demo使用就行。这里重写一下 SDK 的请求过程。

index.php

 <?php
session_start(); include_once( 'config.php' );
include_once( 'saetv2.ex.class.php' ); $o = new SaeTOAuthV2( WB_AKEY , WB_SKEY );
//获取请求 request_token 的 url
$code_url = $o->getAuthorizeURL( WB_CALLBACK_URL ); ?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>新浪微博登录</title>
</head> <body>
<!-- 授权按钮 -->
<p><a href="<?php echo $code_url?>"><img src="weibo_login.png" title="点击进入授权页面" alt="点击进入授权页面" border="0" /></a></p>
</body>
</html>

主要做的事情和I获取 请求    request_token 的url。然后跳转到官方提供的授权页面:

授权之后会重定向到回调 callback.pho.

 <?php
session_start(); include_once( 'config.php' );
include_once( 'saetv2.ex.class.php' ); $o = new SaeTOAuthV2( WB_AKEY , WB_SKEY ); if (isset($_REQUEST['code'])) {
$keys = array();
$keys['code'] = $_REQUEST['code'];
$keys['redirect_uri'] = WB_CALLBACK_URL;
try {
$token = $o->getAccessToken( 'code', $keys ) ;
} catch (OAuthException $e) {
}
} if ($token) {
$_SESSION['token'] = $token;
setcookie( 'weibojs_'.$o->client_id, http_build_query($token) );
?>
授权完成,<a href="weibolist.php">进入你的微博列表页面</a><br />
<?php
} else {
?>
授权失败。
<?php
}
?>

这一步主要是根据授权之后返回的 code 进行调用,请求 acess_token。

前面两部的方法 ,都在

saetv2.ex.class.php里实现,代码如下:

 <?php
/**
* @ignore
*/
class OAuthException extends Exception {
// pass
} /**
* 新浪微博 OAuth 认证类(OAuth2)
*
* 授权机制说明请大家参考微博开放平台文档:{@link http://open.weibo.com/wiki/Oauth2}
*
* @package sae
* @author Elmer Zhang
* @version 1.0
*/
class SaeTOAuthV2 { public $client_id;
public $client_secret;
public $access_token;
public $http_code;
public $url;
public $host = "https://api.weibo.com/2/";
public $timeout = 30;
public $connecttimeout = 30;
public $ssl_verifypeer = FALSE;
public $format = 'json';
public $decode_json = TRUE;
public $http_info;
public $useragent = 'Sae T OAuth2 v0.1';
public $debug = FALSE;
public static $boundary = ''; /**
* Set API URLS
*/
/**
* @ignore
*/
function accessTokenURL() { return 'https://api.weibo.com/oauth2/access_token'; }
/**
* @ignore
*/
function authorizeURL() { return 'https://api.weibo.com/oauth2/authorize'; } /**
* construct WeiboOAuth object
*/
function __construct($client_id, $client_secret, $access_token = NULL) {
$this->client_id = $client_id;
$this->client_secret = $client_secret;
$this->access_token = $access_token;
} /**
* authorize接口
*
* 对应API:{@link http://open.weibo.com/wiki/Oauth2/authorize Oauth2/authorize}
*
* @param string $url 授权后的回调地址,站外应用需与回调地址一致,站内应用需要填写canvas page的地址
* @param string $response_type 支持的值包括 code 和token 默认值为code
* @param string $state 用于保持请求和回调的状态。在回调时,会在Query Parameter中回传该参数
* @param string $display 授权页面类型 可选范围:
* - default 默认授权页面
* - mobile 支持html5的手机
* - popup 弹窗授权页
* - wap1.2 wap1.2页面
* - wap2.0 wap2.0页面
* - js js-sdk 专用 授权页面是弹窗,返回结果为js-sdk回掉函数
* - apponweibo 站内应用专用,站内应用不传display参数,并且response_type为token时,默认使用改display.授权后不会返回access_token,只是输出js刷新站内应用父框架
* @return array
*/
function getAuthorizeURL( $url, $response_type = 'code', $state = NULL, $display = NULL ) {
$params = array();
$params['client_id'] = $this->client_id;
$params['redirect_uri'] = $url;
$params['response_type'] = $response_type;
$params['state'] = $state;
$params['display'] = $display;
return $this->authorizeURL() . "?" . http_build_query($params);
} /**
* access_token接口
*
* 对应API:{@link http://open.weibo.com/wiki/OAuth2/access_token OAuth2/access_token}
*
* @param string $type 请求的类型,可以为:code, password, token
* @param array $keys 其他参数:
* - 当$type为code时: array('code'=>..., 'redirect_uri'=>...)
* - 当$type为password时: array('username'=>..., 'password'=>...)
* - 当$type为token时: array('refresh_token'=>...)
* @return array
*/
function getAccessToken( $type = 'code', $keys ) {
$params = array();
$params['client_id'] = $this->client_id;
$params['client_secret'] = $this->client_secret;
if ( $type === 'code' ) {
$params['grant_type'] = 'authorization_code';
$params['code'] = $keys['code'];
$params['redirect_uri'] = $keys['redirect_uri'];
} else {
throw new OAuthException("wrong auth type");
} $response = $this->oAuthRequest($this->accessTokenURL(), 'POST', $params);
$token = json_decode($response, true);
if ( is_array($token) && !isset($token['error']) ) {
$this->access_token = $token['access_token'];
} else {
throw new OAuthException("get access token failed." . $token['error']);
}
return $token;
} /**
* Format and sign an OAuth / API request
*
* @return string
* @ignore
*/
function oAuthRequest($url, $method, $parameters, $multi = false) { if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
$url = "{$this->host}{$url}.{$this->format}";
} switch ($method) {
case 'GET':
$url = $url . '?' . http_build_query($parameters);
return $this->http($url, 'GET');
default:
$headers = array();
if (!$multi && (is_array($parameters) || is_object($parameters)) ) {
$body = http_build_query($parameters);
} else {
$body = self::build_http_query_multi($parameters);
$headers[] = "Content-Type: multipart/form-data; boundary=" . self::$boundary;
}
return $this->http($url, $method, $body, $headers);
}
} /**
* Make an HTTP request
*
* @return string API results
* @ignore
*/
function http($url, $method, $postfields = NULL, $headers = array()) {
$this->http_info = array();
$ci = curl_init();
/* Curl settings */
curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ci, CURLOPT_ENCODING, "");
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
curl_setopt($ci, CURLOPT_HEADER, FALSE); switch ($method) {
case 'POST':
curl_setopt($ci, CURLOPT_POST, TRUE);
if (!empty($postfields)) {
curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
$this->postdata = $postfields;
}
break;
case 'DELETE':
curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
if (!empty($postfields)) {
$url = "{$url}?{$postfields}";
}
} if ( isset($this->access_token) && $this->access_token )
$headers[] = "Authorization: OAuth2 ".$this->access_token; $headers[] = "API-RemoteIP: " . $_SERVER['REMOTE_ADDR'];
curl_setopt($ci, CURLOPT_URL, $url );
curl_setopt($ci, CURLOPT_HTTPHEADER, $headers );
curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE ); $response = curl_exec($ci);
$this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
$this->http_info = array_merge($this->http_info, curl_getinfo($ci));
$this->url = $url; if ($this->debug) {
echo "=====post data======\r\n";
var_dump($postfields); echo '=====info====='."\r\n";
print_r( curl_getinfo($ci) ); echo '=====$response====='."\r\n";
print_r( $response );
}
curl_close ($ci);
return $response;
} /**
* Get the header info to store.
*
* @return int
* @ignore
*/
function getHeader($ch, $header) {
$i = strpos($header, ':');
if (!empty($i)) {
$key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
$value = trim(substr($header, $i + 2));
$this->http_header[$key] = $value;
}
return strlen($header);
} /**
* @ignore
*/
public static function build_http_query_multi($params) {
if (!$params) return ''; uksort($params, 'strcmp'); $pairs = array(); self::$boundary = $boundary = uniqid('------------------');
$MPboundary = '--'.$boundary;
$endMPboundary = $MPboundary. '--';
$multipartbody = ''; foreach ($params as $parameter => $value) { if( in_array($parameter, array('pic', 'image')) && $value{0} == '@' ) {
$url = ltrim( $value, '@' );
$content = file_get_contents( $url );
$array = explode( '?', basename( $url ) );
$filename = $array[0]; $multipartbody .= $MPboundary . "\r\n";
$multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . '"; filename="' . $filename . '"'. "\r\n";
$multipartbody .= "Content-Type: image/unknown\r\n\r\n";
$multipartbody .= $content. "\r\n";
} else {
$multipartbody .= $MPboundary . "\r\n";
$multipartbody .= 'content-disposition: form-data; name="' . $parameter . "\"\r\n\r\n";
$multipartbody .= $value."\r\n";
} } $multipartbody .= $endMPboundary;
return $multipartbody;
}
}
?>

getAuthorizeURL 方法是用来获取请求 request_token的地址。

getAccessToken 方法是获取 access_token

oAuthRequest 方法是用来发送请求

getHeader 我没发现有地方调用,但是没有他有不行,暂时不知道为什么。

至此Oauth认证结束。

认证就是为了得倒 access_token。本来我是要爬数据。才为了登录。后来发现直接使用 新浪的 api 测试接口,自动生成access_token。爬虫就直接用。当然,早没有发现,才促使我去研究了 Oauth认证,额外的收获吧。总而言之,人总是在逼迫中才能进步。

新浪微博API Oauth2.0 认证的更多相关文章

  1. 新浪微博 使用OAuth2.0调用API

    # -*- coding: cp936 -*- #python 2.7.10 #xiaodeng #新浪微博 使用OAuth2.0调用API #微博开放接口的调用,都需要获取用户的身份认证.目前微博开 ...

  2. Oauth2.0 认证的Web api例子

    Oauth2.0的解释 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容.OA ...

  3. .Net WebApi 实现OAuth2.0认证

    现在多数公众平台提供的api都使用OAuth2.0认证模式,最近在搞Android方面的开发,身份认证和权限控制的各方面比较来说,使用OAuth认证的还是比较靠谱,OAuth2.0的协议可以参考htt ...

  4. Owin中间件搭建OAuth2.0认证授权服务体会

    继两篇转载的Owin搭建OAuth 2.0的文章,使用Owin中间件搭建OAuth2.0认证授权服务器和理解OAuth 2.0之后,我想把最近整理的资料做一下总结. 前两篇主要是介绍概念和一个基本的D ...

  5. 使用Owin中间件搭建OAuth2.0认证授权服务器

    前言 这里主要总结下本人最近半个月关于搭建OAuth2.0服务器工作的经验.至于为何需要OAuth2.0.为何是Owin.什么是Owin等问题,不再赘述.我假定读者是使用Asp.Net,并需要搭建OA ...

  6. C# 网络编程之豆瓣OAuth2.0认证具体解释和遇到的各种问题及解决

            近期在帮人弄一个豆瓣API应用,在豆瓣的OAuth2.0认证过程中遇到了各种问题,同一时候自己须要一个个的尝试与解决,终于完毕了豆瓣API的訪问.作者这里就不再吐槽豆瓣的认证文档了,毕 ...

  7. OAuth2.0认证介绍

    OAuth2.0鉴权 返回 目录 [隐藏] 1 腾讯微博OAuth2.0认证介绍 2 获取accesstoken的两种方式 2.1 1.Authorization code grant 2.1.1 第 ...

  8. Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务

    API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...

  9. OAuth2.0认证和授权以及单点登录

    https://www.cnblogs.com/shizhiyi/p/7754721.html OAuth2.0认证和授权机制讲解 2017-10-30 15:33 by shizhiyi, 2273 ...

随机推荐

  1. 掌握这些技能玩转iOS

    近一年来,苹果iOS/OS X频繁被爆出重大安全漏洞,攻击者可以通过漏洞窃取多达上千个应用的密码.这些漏洞一旦被黑客掌握.利用,后果不堪设想. 好在这些漏洞的发现者还是有节操的,他们都将这些漏洞汇报给 ...

  2. 硬件-ESP32S模块资料

    1.产品概述 ESP-32S WiFi 模块是由安信可科技自主设计研发,该模块核心处理器 ESP32提供了一套完整的802.11 b/g/n/e/i 无线局域网(WLAN)和蓝牙4.2解决方案,具有最 ...

  3. 罗技G502设置

    这个鼠标默认内置了3个档案模式,用G9键来调节. p2 蓝色 1个灯 p2 蓝色 2个灯 p3 蓝色 3个灯 如此循环设置

  4. IOS 公司标示和方向域名

    1. 公司标示使用反向域名========================================正向域名 www.baidu.com 用来标示一台网络主机反向域名 cn.itcast.Myd ...

  5. IOS 多线程-pthread

    #import <pthread.h> @interface HMViewController () - (IBAction)btnClick; @end @implementation ...

  6. bpclntcmd一条神奇的命令,解决新安装nbu客户端无法连接的问题 (屡试不爽神命令)

    1. bpclntcmd案例 bpclntcmd -clear_host_cache bpclntcmd – 测试 NetBackup 系统的功能,并在 NetBackup 客户端上启用光纤传输服务 ...

  7. python 3+djanjo 2.0.7简单学习(三)--Django 管理页面

    django里自带了一个管理页面,也就是后台,下面来学习一下 1.创建超级管理员 python manage.py createsuperuser 键入你想要使用的用户名,然后按下回车键: Usern ...

  8. 2017.10.18 微机原理与接口----汇编语言语法和DOS功能调用

    4.1 汇编语言中的基本数据 ·标识符 ·常数 ·变量具有三个属性: (1)段地址(SEG):变量所在段的段地址 (2)偏移地址(OFFSET):变量所在段内的偏移地址 (3)类型(TYPE):每个变 ...

  9. assert函数和捕获异常

    assert函数: C语言和C++都有一个专为调试而准备的工具函数,就是 assert()函数. 这个函数是在C语言的 assert.h 库文件里定义的,所以包含到C++程序里我们用以下语句: #in ...

  10. mysql关键字了解

    unsigned  无符号 就是没有负数 列-1  -2 auto_increment 自增 comment 注释 primary key 主键 foreign key ()   references ...