This commit is contained in:
195
Sinauth/AuthorizeAction.php
Normal file
195
Sinauth/AuthorizeAction.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/**
|
||||
* Sinauth Plugin
|
||||
*
|
||||
* @copyright Copyright (c) 2015 jimmy.chaw (http://x3d.cnblogs.com)
|
||||
* @license GNU General Public License 2.0
|
||||
*
|
||||
*/
|
||||
|
||||
class Sinauth_AuthorizeAction extends Typecho_Widget implements Widget_Interface_Do
|
||||
{
|
||||
private $db;
|
||||
private $config;
|
||||
private static $pluginName = 'Sinauth';
|
||||
private static $tableName = 'users_oauth';
|
||||
|
||||
public function __construct($request, $response, $params = NULL)
|
||||
{
|
||||
parent::__construct($request, $response, $params);
|
||||
$this->config = Helper::options()->plugin(self::$pluginName);
|
||||
$this->db = Typecho_Db::get();
|
||||
}
|
||||
|
||||
public function action(){
|
||||
//跳转
|
||||
if (!class_exists('SaeTOAuthV2')) {
|
||||
require_once 'saetv2.ex.class.php';
|
||||
}
|
||||
$saeto_client = new SaeTOAuthV2($this->config->client_id, $this->config->client_secret);
|
||||
$authorize_url = $saeto_client->getAuthorizeURL($this->config->callback_url, 'code');
|
||||
$this->response->redirect($authorize_url);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权回调地址
|
||||
*/
|
||||
public function callback(){
|
||||
if(empty($_GET['code'])) {
|
||||
throw new Typecho_Exception(_t('无效请求!'));
|
||||
}
|
||||
|
||||
//跳转
|
||||
if (!class_exists('SaeTOAuthV2')) {
|
||||
require_once 'saetv2.ex.class.php';
|
||||
}
|
||||
|
||||
$saeto_client = new SaeTOAuthV2($this->config->client_id, $this->config->client_secret);
|
||||
//取access_token
|
||||
$access_token = $saeto_client->getAccessToken('code', array('code' => trim($_GET['code']), 'redirect_uri' => $this->config->callback_url));
|
||||
|
||||
if (empty($access_token) || !is_array($access_token) || empty($access_token['uid'])) {
|
||||
throw new Typecho_Exception(_t('获取access_token失败,请返回重新授权!'));
|
||||
}
|
||||
|
||||
$table = $this->db->getPrefix() . self::$tableName;
|
||||
$query = $this->db->query("SELECT * FROM {$table} WHERE openid='{$access_token['uid']}' AND plateform='sina'");
|
||||
$users_oauth = $this->db->fetchRow($query);
|
||||
|
||||
if (!empty($users_oauth['uid'])) { //该新浪帐号已经绑定了用户
|
||||
if (Typecho_Widget::widget('Widget_User')->hasLogin()) { /** 直接返回 */
|
||||
|
||||
$this->response->redirect(Typecho_Widget::widget('Widget_Options')->index);
|
||||
} else { //让其直接登陆
|
||||
$this->setUserLogin($users_oauth['uid']);
|
||||
|
||||
if (!Typecho_Widget::widget('Widget_User')->pass('contributor', true)) {
|
||||
/** 不允许普通用户直接跳转后台 */
|
||||
$this->response->redirect(Typecho_Widget::widget('Widget_Options')->profileUrl);
|
||||
} else {
|
||||
$this->response->redirect(Typecho_Widget::widget('Widget_Options')->adminUrl);
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
//该新浪帐号未绑定过
|
||||
|
||||
/** 如果已经登录 */
|
||||
if (Typecho_Widget::widget('Widget_User')->hasLogin()) {
|
||||
/** 直接绑定 */
|
||||
$cookieUid = Typecho_Cookie::get('__typecho_uid');
|
||||
$this->bindOauthUser($cookieUid, $access_token['uid'], 'sina', $access_token['expires_in']);
|
||||
|
||||
$this->response->redirect(Typecho_Widget::widget('Widget_Options')->index);
|
||||
} else {
|
||||
//取用户信息
|
||||
$saetc_client = new SaeTClientV2($this->config->client_id, $this->config->client_secret, $access_token['access_token']);
|
||||
|
||||
$weibo_user = $saetc_client->show_user_by_id($access_token['uid']);
|
||||
|
||||
//创建用户
|
||||
$uid = $this->registerFromWeiboUser($weibo_user);
|
||||
|
||||
if (!$uid) {
|
||||
throw new Typecho_Exception(_t('创建帐号失败,请联系管理员!'));
|
||||
}
|
||||
|
||||
$this->setUserLogin($uid);
|
||||
|
||||
$this->bindOauthUser($uid, $access_token['uid'], 'sina', $access_token['expires_in']);
|
||||
|
||||
$this->response->redirect(Typecho_Widget::widget('Widget_Options')->profileUrl);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//构造用户帐号
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据微博用户信息创建帐号
|
||||
*/
|
||||
protected function registerFromWeiboUser(&$weibo_user) {
|
||||
$hasher = new PasswordHash(8, true);
|
||||
$generatedPassword = Typecho_Common::randString(7);
|
||||
|
||||
//TODO 用户名重复的问题
|
||||
|
||||
$uname = $weibo_user['name'];
|
||||
|
||||
$i = 0;
|
||||
if (!Typecho_Widget::widget('Widget_Abstract_Users')->nameExists($uname)) { //用户名存在
|
||||
echo 'here';
|
||||
for ($i = 1; $i < 999; $i++) {
|
||||
echo $i;
|
||||
if (Typecho_Widget::widget('Widget_Abstract_Users')->nameExists($uname . '_' . $i)) {
|
||||
$uname = $uname . '_' . $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dataStruct = array(
|
||||
'name' => $uname,
|
||||
'mail' => $weibo_user['idstr'] . ($i ? '_' . $i : '') . '@localhost.local',
|
||||
'screenName'=> $weibo_user['screen_name'] . ($i ? '_' . $i : ''),
|
||||
'password' => $hasher->HashPassword($generatedPassword),
|
||||
'created' => time(),
|
||||
'url' => $weibo_user['url'],
|
||||
'group' => 'subscriber'
|
||||
);
|
||||
|
||||
$insertId = Typecho_Widget::widget('Widget_Abstract_Users')->insert($dataStruct);
|
||||
|
||||
return $insertId;
|
||||
}
|
||||
|
||||
public function nameExists($name)
|
||||
{
|
||||
$select = $this->db->select()
|
||||
->from('table.users')
|
||||
->where('name = ?', $name)
|
||||
->limit(1);
|
||||
|
||||
$user = $this->db->fetchRow($select);
|
||||
|
||||
return $user ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户登陆状态
|
||||
*/
|
||||
protected function setUserLogin($uid, $expire = 30243600) {
|
||||
Typecho_Widget::widget('Widget_User')->simpleLogin($uid);
|
||||
|
||||
$authCode = function_exists('openssl_random_pseudo_bytes') ?
|
||||
bin2hex(openssl_random_pseudo_bytes(16)) : sha1(Typecho_Common::randString(20));
|
||||
|
||||
Typecho_Cookie::set('__typecho_uid', $uid, time() + $expire);
|
||||
Typecho_Cookie::set('__typecho_authCode', Typecho_Common::hash($authCode), time() + $expire);
|
||||
|
||||
//更新最后登录时间以及验证码
|
||||
$this->db->query($this->db
|
||||
->update('table.users')
|
||||
->expression('logged', 'activated')
|
||||
->rows(array('authCode' => $authCode))
|
||||
->where('uid = ?', $uid));
|
||||
}
|
||||
|
||||
public function bindOauthUser($uid, $openid, $plateform = 'sina', $expires_in = 0) {
|
||||
$rows = array(
|
||||
'openid' => $openid,
|
||||
'uid' => $uid,
|
||||
'plateform' => $plateform,
|
||||
'bind_time' => time(),
|
||||
'expires_in' => $expires_in
|
||||
);
|
||||
return $this->db->query($this->db->insert('table.users_oauth')->rows($rows));
|
||||
}
|
||||
}
|
||||
129
Sinauth/Plugin.php
Normal file
129
Sinauth/Plugin.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* Sina 微博登陆插件
|
||||
*
|
||||
* @package Sinauth
|
||||
* @author jimmy chaw
|
||||
* @version 1.0.0 Beta
|
||||
* @link http://x3d.cnblogs.com
|
||||
*/
|
||||
class Sinauth_Plugin implements Typecho_Plugin_Interface
|
||||
{
|
||||
private static $pluginName = 'Sinauth';
|
||||
private static $tableName = 'users_oauth';
|
||||
|
||||
/**
|
||||
* 激活插件方法,如果激活失败,直接抛出异常
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function activate()
|
||||
{
|
||||
$meg = self::install();
|
||||
|
||||
Typecho_Plugin::factory('Widget_User')->___sinauthAuthorizeIcon = array('Sinauth_Plugin', 'authorizeIcon');
|
||||
|
||||
Helper::addAction('sinauthAuthorize', 'Sinauth_AuthorizeAction');
|
||||
Helper::addRoute('sinauthAuthorize', '/sinauthAuthorize/', 'Sinauth_AuthorizeAction', 'action');
|
||||
Helper::addRoute('sinauthCallback', '/sinauthCallback/', 'Sinauth_AuthorizeAction', 'callback');
|
||||
Helper::addPanel(1, 'Sinauth/panel.php', 'Sinauth', 'Sinauth用户管理', 'administrator');
|
||||
|
||||
return _t($meg.'。请进行<a href="options-plugin.php?config='.self::$pluginName.'">初始化设置</a>');
|
||||
}
|
||||
|
||||
public static function install()
|
||||
{
|
||||
|
||||
$installDb = Typecho_Db::get();
|
||||
$type = array_pop(explode('_',$installDb->getAdapterName()));
|
||||
$prefix = $installDb->getPrefix();
|
||||
$oauthTable = $prefix. self::$tableName;
|
||||
try {
|
||||
$installDb->query("CREATE TABLE `$oauthTable` (
|
||||
`moid` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`plateform` varchar(45) NOT NULL DEFAULT 'sina',
|
||||
`uid` int(10) unsigned NOT NULL,
|
||||
`openid` varchar(80) NOT NULL,
|
||||
`bind_time` int(10) unsigned NOT NULL,
|
||||
`expires_in` int(10) unsigned DEFAULT NULL,
|
||||
`refresh_token` varchar(300) DEFAULT NULL,
|
||||
PRIMARY KEY (`moid`),
|
||||
KEY `uid` (`uid`),
|
||||
KEY `plateform` (`plateform`),
|
||||
KEY `openid` (`openid`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8");
|
||||
|
||||
return('表创建成功, 插件已经被激活!');
|
||||
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
$code = $e->getCode();
|
||||
if(('Mysql' == $type && (1050||'42S01') == $code)) {
|
||||
$script = 'SELECT `moid` from `' . $oauthTable . '`';
|
||||
$installDb->query($script, Typecho_Db::READ);
|
||||
return '数据表已存在,插件启用成功';
|
||||
} else {
|
||||
throw new Typecho_Plugin_Exception('数据表'.$oauthTable.'建立失败,插件启用失败。错误号:'.$code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//在前台登陆页面增加oauth跳转图标
|
||||
public static function authorizeIcon() {
|
||||
return '<a href="' . Helper::options()->index . '/sinauthAuthorize">新浪登陆</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用插件方法,如果禁用失败,直接抛出异常
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return void
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function deactivate(){
|
||||
Helper::removeRoute('sinauthAuthorize');
|
||||
Helper::removeRoute('sinauthCallback');
|
||||
Helper::removeAction('sinauthAuthorize');
|
||||
|
||||
Helper::removePanel(1, 'Sinauth/panel.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件配置面板
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Widget_Helper_Form $form 配置面板
|
||||
* @return void
|
||||
*/
|
||||
public static function config(Typecho_Widget_Helper_Form $form)
|
||||
{
|
||||
$client_id = new Typecho_Widget_Helper_Form_Element_Text('client_id', NULL,'', _t('App Key'),'请在微博开放平台查看http://open.weibo.com');
|
||||
$form->addInput($client_id);
|
||||
|
||||
$client_secret = new Typecho_Widget_Helper_Form_Element_Text('client_secret', NULL,'', _t('App Secret'),'请在微博开放平台查看http://open.weibo.com');
|
||||
$form->addInput($client_secret);
|
||||
|
||||
$callback_url = new Typecho_Widget_Helper_Form_Element_Text('callback_url', NULL,'http://', _t('回调地址'),'请与微博开放平台中设置一致');
|
||||
$form->addInput($callback_url);
|
||||
|
||||
//$callback_url = new Typecho_Widget_Helper_Form_Element_Text('email_domain', NULL,'v.sina.com', _t('虚拟email后缀'),'创建用户帐号时构造一个虚拟email,如uid@v.sina.com');
|
||||
//$form->addInput($callback_url);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 个人用户的配置面板
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Widget_Helper_Form $form
|
||||
* @return void
|
||||
*/
|
||||
public static function personalConfig(Typecho_Widget_Helper_Form $form){
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
39
Sinauth/README.md
Normal file
39
Sinauth/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 新浪OAuth2登陆插件
|
||||
|
||||
基于最新新浪sae维护的sdk lib https://github.com/xiaosier/libweibo。
|
||||
|
||||
> 修正登录路径、面板兼容和数据库检测问题,更新文档。
|
||||
|
||||
实现功能:
|
||||
* 新用户进入授权流程后,自动创建帐号并登陆
|
||||
* 已登陆但未绑定过的用户进入授权流程后,会绑定当前帐号
|
||||
* 已绑定过用户授权直接登陆
|
||||
* 后台微信授权用户简易列表
|
||||
|
||||
安装插件后还需要进行一些设置。
|
||||
|
||||
第一步需要设定好微博开放平台的回调地址:
|
||||
|
||||
去微博开放平台打开你的应用,切换到“接口管理”|“授权机制”页面,看到“OAuth2.0 授权设置”,点击编辑,设置相应url:
|
||||
|
||||
授权回调页:http://你的域名/sinauthCallback
|
||||
|
||||
取消授权回调页:http://你的域名/sinauthCancel 这个暂时没有实现,不影响基本使用
|
||||
|
||||
注:建议启用路径重写,否则,上述url需要稍作调整,加上入口文件。
|
||||
|
||||
|
||||
第二步需要在模板中相应地方增加相应链接:
|
||||
|
||||
/app_path/usr/themes/default/sidebar.php
|
||||
|
||||
```php
|
||||
<li class="last"><?php $this->user->sinauthAuthorizeIcon(); ?>
|
||||
```
|
||||
也可以在后台登陆页面加一个:
|
||||
|
||||
/app_path/admin/login.php
|
||||
|
||||
```php
|
||||
<?php echo $user->sinauthAuthorizeIcon(); ?>•
|
||||
```
|
||||
78
Sinauth/panel.php
Normal file
78
Sinauth/panel.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
include 'header.php';
|
||||
include 'menu.php';
|
||||
?>
|
||||
<div class="main">
|
||||
<div class="body container">
|
||||
<?php include 'page-title.php'; ?>
|
||||
<div class="container typecho-page-main" role="form">
|
||||
<div id="MostCacheMain" class="col-mb-12 typecho-list">
|
||||
|
||||
<div id="tab-cacheman" class="tab-content">
|
||||
|
||||
<div class="typecho-table-wrap">
|
||||
<table class="typecho-list-table">
|
||||
<colgroup>
|
||||
<col width="40%"/>
|
||||
<col width="20%"/>
|
||||
<col width="20%"/>
|
||||
<col width="10%"/>
|
||||
<col width="10%"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('用户'); ?></th>
|
||||
<th><?php _e('openid'); ?></th>
|
||||
<th><?php _e('创建时间'); ?> </th>
|
||||
<th><?php _e('过期时间'); ?> </th>
|
||||
<th><?php _e('操作'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $page = isset($request->page) ? $request->page : 1 ; ?>
|
||||
<?php $users = $db->fetchAll($db->select()->from('table.users_oauth')->join('table.users', 'table.users_oauth.uid=table.users.uid')->page($page, 15)->order('table.users_oauth.bind_time', Typecho_Db::SORT_DESC)); ?>
|
||||
<?php foreach($users as $user): ?>
|
||||
<tr class="even" >
|
||||
<td>
|
||||
[<?php echo $user['uid']; ?>] <?php echo $user['name']; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $user['openid']; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo date('Y-m-d H:i:s', $user['bind_time']); ?>
|
||||
</td>
|
||||
<td><?php if($user['expires_in']) {echo date('H:i:s', $user['expires_in']);} ?></td>
|
||||
|
||||
<td>
|
||||
-
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="typecho-pager">
|
||||
<div class="typecho-pager-content">
|
||||
<ul>
|
||||
<?php $total = $db->fetchObject($db->select(array('COUNT(uid)' => 'num'))->from('table.users_oauth'))->num; ?>
|
||||
<?php for($i=1;$i<=ceil($total/15);$i++): ?>
|
||||
<li class='current'><a href="<?php $options->adminUrl('extending.php?panel=Sinauth%2Fpanel.php&page='.$i); ?>" style= 'cursor:pointer;' title='第 <?php _e($i); ?> 页'> <?php _e($i); ?> </a></li>
|
||||
<?php endfor; ?>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
include 'copyright.php';
|
||||
include 'common-js.php';
|
||||
include 'footer.php';
|
||||
include 'table-js.php';
|
||||
?>
|
||||
|
||||
3295
Sinauth/saetv2.ex.class.php
Normal file
3295
Sinauth/saetv2.ex.class.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user