之前谈的两篇《Authentication和Authrization(上)、(下)》以空谈为主,算是一个开头,原文最后有说要一一整些实现出来的。那么现在就开始吧,不过介绍的顺序则先从相对简单的OAuth 2.0开始。
foursquare 第一版的API是基于BasicAuth的,也就是基于HTTP Authentication的一种基本验证方式,这种方式的优点是非常简单,只要在HTTP Header里加一个字段就行了,但缺点是用户名密码会被直接暴露在传输过程中,虽然经过了Base64编码,但是解码它是一件非常容易的事情,除非使用 HTTPS,否则是非常不安全的。
之前因为我用的手机是智障机,跑不了官方客户端,官方网页端又被墙,用起来很不方便,所以自己参考了dabr的代码,用PHP4写过一个网页客户端程序。
不 过后来foursquare出于安全和功能考虑,完全抛弃了第一版的API,推出了全新的第二版API。这个版本的特点是:完全重新设计了API的架构, 更加符合REST规范,特别是身份验证改用了更安全的OAuth 2.0,并且使用了HTTPS。到今年8月1号的时候,foursquare关闭了对第一版API的支持,全面转到第二版API。为了让我的程序能够继续 使用,我不得不赶在这一转换之前几天,把程序完全改写了——顺便增加了一些功能。
当然,本文不打算详细讨论foursquare的API,只谈谈登录的部分。
根据foursquare的Authentication文档说明,全部的过程可以分为三大步:
1、在foursquare注册一个应用,取得一个client_id;
2、通过OAuth 2.0验证,取得access_token;
3、使用access_token调用foursquare API。
其中第一步没什么好说的,照着说明去做就是了,这里要从技术上讨论的主要是第二步,并且需要用第三步来验证第二步的结果。
单就第二步取得access_token来说,也可以分为以下步骤:
1、 先转向到foursquare的授权页面,并提交client_id和redirect_uri(其它参数见文档或代码)。redirect_uri为验 证通过后的回调链接,即在注册应用时提供的那个回调链接,通常二者需要保持一致,不过只要client_secret保管好,即使这里允许不一致(说明: 我倒没试过不一致会如何)也不会导致client_id被盗用;
2、foursquare收到请求后根据以下情况作出判断:如果你还未登录foursquare,则提示你登录;如果你已经登录,但未授权此应用,则提示你是否要授权;如果已经授权,则重向到redirect_uri,并同时提交一个code;
3、 应用收到转来的请求后就可以向foursquare请求获取access_token了,请求参数包括 client_id,client_secret(相当于应用密码,这个一定要保管好),code等(其它参数见文档或代码),只要这个code没错,就 可以取得access_token。
之后就可以用这个access_token去调用foursquare API了。
需要注意的是:这个access_token是一个用户对一个应用授权的唯一标识,一定要保管好,不可泄露。当然,如果万一泄露,应用的开发者应该及时到foursquare的应用管理页面重新生成client_id/client_secret。
具体的登录代码如下:
function login_foursquare() {
session_start();
$GLOBALS['user']['type'] = 'oauth';
$oauth_code = $_GET['code'];
if (isset($oauth_code)) { // 来自foursquare的回调请求含有code参数
$params = array('client_id' => OAUTH2_CLIENT_ID,
'client_secret' => OAUTH2_CLIENT_SECRET,
'grant_type' => 'authorization_code',
'redirect_uri' => CALLBACK_URL,
'code' => $oauth_code);
$result = do_sf_process(SF_OAUTH2.'access_token?'.http_build_query($params)); // 向foursquare请求access_token
$access_token = $result->access_token;
$redir = $_SESSION['redir'];
unset($_SESSION['redir']);
$GLOBALS['user']['password'] = $access_token;
sf_user_info();
_user_save_cookie(1);
header('Location: '. $redir);
exit();
} else { // 来自用户的登录访问,不含code参数
_user_decrypt_cookie($_COOKIE['USER_AUTH']);
$redir = isset($_GET['redir']) ? $_GET['redir'] : $_SERVER['HTTP_REFERER'];
$_SESSION['redir'] = $redir;
$authorise_url = SF_OAUTH2.'authenticate?'.http_build_query(
array( 'client_id' => OAUTH2_CLIENT_ID,
'response_type' => 'code',
'redirect_uri' => CALLBACK_URL));
header("Location: $authorise_url"); // 重定向到foursquare的授权页面
}
}
至于取得access_token以后的API调用,所要做的事情就只是把access_token附加到每次调用的参数里即可。
function user_oauth_sign(&$url, &$args) {
$method = $args !== false ? 'POST' : 'GET';
if (preg_match_all('#[?&]([^=]+)=([^&]+)#', $url, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$args[$match[1]] = $match[2];
}
$url = substr($url, 0, strpos($url, '?'));
}
$args['oauth_token'] = $GLOBALS['user']['password'];
if ($method == 'GET'){
$url = $url."?".http_build_query($args);
$args = false;
}
}
function sf_process($url, $post_data = false) {
if (user_type() == 'oauth' && (strpos($url, SF_API) !== false)) {
user_oauth_sign($url, $post_data);
}
$result = do_sf_process($url, $post_data);
return $result->response;
}
整个客户端代码下载在Google Code。
推送到[go4pro.org]