在上一篇文章我们讲了wordpress设置页的编码,这篇文章里我们讲oauth2鉴权,也就是从osc open api中获取access token的过程。有了access token ,我们才能调用osc的相关接口。 原理和流程请先阅读 http://www.oschina.net/openapi/docs ,你首先需要理解这个流程,然后才能考虑用wordpress实现。其中上一节出现的
$this->callback_url = add_query_arg('callback', 'oscpress', site_url());
就是你填在osc open api中的回调url http://域名?callback=oscpress。首先我们向构造函数里添加两个新的action,
add_action('query_vars', array(&$this, 'add_query_vars'));
add_action("parse_request", array(&$this, 'callback'));
接下来我们来写回调的方法:
// 增加一个新的公共查询参数
public function add_query_vars($public_query_vars) {
$public_query_vars[] = 'callback';
return $public_query_vars;
}
// osc open api url的回传后执行
public function callback($request)
{
if (isset($request->query_vars['callback']) && $request->query_vars['callback'] == 'oscpress') {
$this->_callback();
exit();
};
}
// 实际执行的回调
protected function _callback(){
}
add_query_vars 方法是加入了一个新的查询参数,不用$_GET['callback'],这样利于日后使用url重写. 不在 callback 直接写逻辑是为了更清晰,在callback中负责各种前置,后置的操作,比如记录到日志,发送邮件等,而_callback只要集中处理回调的逻辑就行了。 接下来我们写一个生成引导用户的验证url的方法,这样当用户点击这个url之后,会跳转到osc的用户授权页。用户授权完成后就能取得access token了
// 生成引导的验证url
protected function _generate_authorize_url() {
$settings = (array) get_option( 'oscpress_settings' );
if(empty($settings)) {
return false;
}
$authorize_url = $this->api_site . '/action/oauth2/authorize';
$args = array(
'response_type' => 'code',
'client_id' => $settings['appid'],
'redirect_uri' => $this->_callback_url,
'state' => wp_create_nonce($this->_state),
);
$authorize_url .= '?' . http_build_query($args);
return $authorize_url;
}
然后改造一下settings_section_text,让它显示授权的链接
public function settings_section_text(){
echo "<hr/>";
$authorize_url = $this->_generate_authorize_url();
if(false === $authorize_url){
echo "<em>填写应用的id及私钥</em>";
}else{
printf("<em><a href='%s'>点击授权</a></em>",$authorize_url);
}
}
点击后会出现osc的授权页,留意url:
用户授权后会跳转回我们的网站,这时我们可以从url中获得code和state参数,接下来在回调方法中验证state参数,并将code参数跟我们的appid,appsecret等作为请求参数,向接口再发送一次请求,换取access token,最后保存token。
// 实际执行的回调
protected function _callback(){
if ( isset($_GET['code']) && isset($_GET['state']) && $this->_verify_state($_GET['state'])) {
$code = $_GET['code'];
$url = $this->api_site . '/action/openapi/token';
$settings = get_option( 'oscpress_settings' );
$args = array(
'client_id' => $settings['appid'],
'client_secret' => $settings['appsecret'],
'grant_type' => 'authorization_code',
'redirect_uri' => $this->_callback_url,
'code' => $code,
'dataType' => 'json'
);
$response = wp_remote_post($url, array('body' => $args));
if (!is_wp_error($response) && $response['response']['code'] == 200) {
$this->_save_token($response['body']);
$redirect_url = admin_url('admin.php?page=oscpress_admin_settings');
wp_redirect($redirect_url);
printf('<script>window.location.href="%s";</script>', $redirect_url);
} elseif (is_wp_error($response)) {
echo "请求出错:" . $response->get_error_message();
} else {
echo "未知错误";
}
} else {
echo "回调失败: 参数错误";
}
}
这样就完成了回调的处理。其中为了保证浏览器兼容性,使用了http响应头跳转和前端script跳转。 需要加入了两个新的protected方法:
protected function _verify_state($state)
{
if ($state !== wp_create_nonce($this->_state)) {
return false;
}
return true;
}
protected function _save_token($token_arr)
{
update_option('oscpress_token', $token_arr);
update_option('oscpress_token_update_at', time());
return true;
}
这时你再点击设置页面的链接,授权后跳转回设置页,似乎什么也没发生? 其实不然,现在系统已经保存了你的access token了,只是你看不到而已,这时我们改写 settings_section_text的内容,显示授权用户的osc信息和access token. 这里要用到osc open api获取用户信息接口,代码如下:
public function settings_section_text(){ echo "<hr/>"; $authorize_url = $this->_generate_authorize_url(); if(false === $authorize_url){ // 未填写应用id和私钥 echo "<em>填写应用的id及私钥</em>"; }elseif( $access_token = $this->_get_access_token() ) { // 已获取access token,显示个人信息 $response = $this->_get_openapi_user(); if(is_wp_error($response)) { echo $response->get_error_message(); } $info_obj = json_decode($response['body']); ?> <span> <img align="absbottom" src="<?php echo $info_obj->avatar; ?>"/><br/> <a href="<?php echo $info_obj->url; ?>" target="_blank"><?php echo $info_obj->name; ?></a> </span> <p>Access Token: <?php echo $access_token;?></p><hr/> <?php }else{ // 未授权,显示授权链接 printf("<em><a href='%s'>点击授权</a></em>",$authorize_url); } }
新加入两个protected方法:
// 获取存储的access token protected function _get_access_token(){ $json_str = get_option('oscpress_token',false); if(false === $json_str) { return false; } $obj = json_decode($json_str); $update_ts = get_option('oscpress_token_update_at',0); if($obj->expires_in + $update_ts <= time() ){ // 过期 return false; } return $obj->access_token; } // 获得用户信息 protected function _get_openapi_user() { $url = $this->api_site . '/action/openapi/user'; $args = array( 'access_token' => $this->_get_access_token(), 'dataType' => 'json' ); $response = wp_remote_post($url, array('body' => $args,'sslverify'=>false)); return $response; }
完成后刷新页面,效果如图:
看起来很不错,不过好像差了些什么东西,比如想清除授权,或者换一个用户怎么办? OK,接下来我们做一个清除授权的链接,修改一下settings_section_text方法,把清除授权的链接放进去,同时小小修改一下界面。当然这个清除只是删除保存在本地的access token,并不是从open api的服务端清除。
<span> <img align="absbottom" src="<?php echo $info_obj->avatar; ?>"/><br/> <p><a href="<?php echo $info_obj->url; ?>" target="_blank"><?php echo $info_obj->name; ?></a></p> <p><a href="<?php echo $this->_clear_authorize_url(); ?>">清除授权</a></p> </span>
然后我们写两个清除授权相关的函数:
// 生成取消授权url protected function _clear_authorize_url(){ return admin_url('admin.php?page=oscpress_admin_settings&action=clear_osc_authorize&_wpnonce=' . wp_create_nonce('clear_osc_authorize')); } // 清除授权信息 protected function _clear_authorize() { return delete_option('oscpress_token') && delete_option('oscpress_token_update_at'); }
最后我们在admin_init方法加入实际清除的逻辑,放在
register_setting( 'oscpress_settings_group', 'oscpress_settings',array($this,'sanitize_callback') );这句的前面。
if($_REQUEST['action'] && $_REQUEST['action']=='clear_osc_authorize'){ if (check_admin_referer('clear_osc_authorize')) { if($this->_clear_authorize()){ add_settings_error('oscpress_settings', 'clear_osc_authorize_failed', "授权信息清除成功", 'updated'); } } }
这里用到了check_admin_referer函数,这个是用来防csrf攻击的。清除成功后会显示一条通知。如图:
好了,osc open api的授权就先到这里了。关于refresh token和其他的内容集中会单独放一篇的补充。