Skip to content

Commit 25943b9

Browse files
committed
Merge commit '2dcbdbc35b6bf7d7857a978426c262796d63cc98' as 'YangCong'
2 parents 005c40b + 2dcbdbc commit 25943b9

File tree

3 files changed

+274
-0
lines changed

3 files changed

+274
-0
lines changed

YangCong/Action.php

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
class YangCong_Action extends Typecho_Widget implements Widget_Interface_Do {
3+
const URL_QRCODE_FOR_BINDING = "https://api.yangcong.com/v2/qrcode_for_binding";
4+
const URL_QRCODE_FOR_AUTH = "https://api.yangcong.com/v2/qrcode_for_auth";
5+
const URL_EVENT_RESULT = "https://api.yangcong.com/v2/event_result";
6+
7+
protected $db, $options, $plugin, $user, $yc_id, $yc_key;
8+
9+
public function __construct($request, $response, $params = NULL) {
10+
parent::__construct($request, $response, $params);
11+
/** 初始化数据库 */
12+
$this->db = Typecho_Db::get();
13+
/** 初始化常用组件 */
14+
$this->options = $this->widget('Widget_Options');
15+
$this->user = $this->widget('Widget_User');
16+
$this->plugin = $this->options->plugin('YangCong');
17+
18+
$this->yc_id = $this->plugin->yc_id;
19+
$this->yc_key = $this->plugin->yc_key;
20+
$this->yc_auth_type = $this->plugin->yc_auth_type;
21+
}
22+
public function execute() {}
23+
24+
public function login(){
25+
$params = array('app_id' => $this->yc_id,
26+
'auth_type' => $this->yc_auth_type,
27+
'signature' => md5("app_id=" . $this->yc_id . "auth_type=" . $this->yc_auth_type . $this->yc_key));
28+
$client = Typecho_Http_Client::get();
29+
$response = $client->setQuery($params)->send(self::URL_QRCODE_FOR_AUTH);
30+
$response = json_decode($response, true);
31+
$this->response->throwJson($response);
32+
}
33+
34+
public function bind(){
35+
if ($this->db->fetchObject($this->db->select(array('COUNT(*)' => 'num'))->from('table.options')->where('name = ? AND user = ?', 'yc_bind_uid', $this->user->uid))->num <= 0) {
36+
$params = array('app_id' => $this->yc_id,
37+
'auth_type' => $this->yc_auth_type,
38+
'signature' => md5("app_id=" . $this->yc_id . "auth_type=" . $this->yc_auth_type . $this->yc_key));
39+
$client = Typecho_Http_Client::get();
40+
$response = $client->setQuery($params)->send(self::URL_QRCODE_FOR_BINDING);
41+
$response = json_decode($response, true);
42+
$this->response->throwJson($response);
43+
}else{
44+
$this->response->throwJson(null);
45+
}
46+
}
47+
48+
public function auth(){
49+
$eventId = $this->request->get("event_id");
50+
$params = array('app_id' => $this->yc_id,
51+
'event_id' => $eventId,
52+
'signature' => md5("app_id=" . $this->yc_id . "event_id=" . $eventId . $this->yc_key));
53+
$client = Typecho_Http_Client::get();
54+
$response = $client->setQuery($params)->send(self::URL_EVENT_RESULT);
55+
$response = json_decode($response, true);
56+
$result = array('status' => $response['status']);
57+
if($response['status'] == 200){
58+
$action = $this->request->get("action");
59+
if($action == 'bind'){
60+
if ($this->db->fetchObject($this->db->select(array('COUNT(*)' => 'num'))->from('table.options')->where('name = ? AND user = ?', 'yc_bind_uid', $this->user->uid))->num > 0) {
61+
$this->widget('Widget_Abstract_Options')->update(array('value' => $response['uid']), $this->db->sql()->where('name = ? AND user = ?', 'yc_bind_uid', $this->user->uid));
62+
} else {
63+
$this->widget('Widget_Abstract_Options')->insert(array(
64+
'name' => 'yc_bind_uid',
65+
'value' => $response['uid'],
66+
'user' => $this->user->uid
67+
));
68+
}
69+
}else if($action == 'login'){
70+
$user = $this->db->fetchRow($this->db->select()->from('table.options')->where('name = ? and value = ?', 'yc_bind_uid', $response['uid'])->limit(1));
71+
72+
if (!empty($user)) {
73+
$authCode = function_exists('openssl_random_pseudo_bytes') ?
74+
bin2hex(openssl_random_pseudo_bytes(16)) : sha1(Typecho_Common::randString(20));
75+
$user['authCode'] = $authCode;
76+
77+
Typecho_Cookie::set('__typecho_uid', $user['user'], 0);
78+
Typecho_Cookie::set('__typecho_authCode', Typecho_Common::hash($authCode), $expire);
79+
80+
//更新最后登录时间以及验证码
81+
$this->db->query($this->db->update('table.users')->expression('logged', 'activated')->rows(array('authCode' => $authCode))->where('uid = ?', $user['user']));
82+
$this->user->simpleLogin($user['user']);
83+
}
84+
85+
/** 跳转验证后地址 */
86+
if (NULL != $this->request->referer) {
87+
$result['redirect'] = $this->request->referer;
88+
} else if (!$this->user->pass('contributor', true)) {
89+
/** 不允许普通用户直接跳转后台 */
90+
$result['redirect'] = $this->options->profileUrl;
91+
} else {
92+
$result['redirect'] = $this->options->adminUrl;
93+
}
94+
}
95+
}
96+
$this->response->throwJson($result);
97+
}
98+
99+
100+
public function action(){
101+
// $this->security->protect();
102+
$this->on($this->request->is('do=auth'))->auth();
103+
$this->on($this->request->is('do=bind'))->bind();
104+
$this->on($this->request->is('do=login'))->login();
105+
}
106+
}
107+
?>

YangCong/Plugin.php

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
/**
3+
* 简单、安全的身份验证服务
4+
*
5+
* @package YangCong
6+
* @author 冰剑
7+
* @version 2.0.0
8+
* @link http://www.binjoo.net
9+
*/
10+
class YangCong_Plugin implements Typecho_Plugin_Interface {
11+
public static function activate() {
12+
Typecho_Plugin::factory('admin/header.php')->header = array('YangCong_Plugin', 'js_header');
13+
Typecho_Plugin::factory('admin/profile.php')->bottom = array('YangCong_Plugin', 'js_profile');
14+
Typecho_Plugin::factory('admin/login.php')->bottom = array('YangCong_Plugin', 'js_login');
15+
Helper::addAction('YangCong', 'YangCong_Action');
16+
return('微信助手已经成功激活,请进入设置Token!');
17+
}
18+
19+
public static function deactivate() {
20+
Helper::removeAction('YangCong');
21+
}
22+
23+
public static function config(Typecho_Widget_Helper_Form $form) {
24+
$yc_id = new Typecho_Widget_Helper_Form_Element_Text('yc_id', NULL, NULL, _t('应用 ID'), '啦啦啦啦');
25+
$form->addInput($yc_id);
26+
27+
$yc_key = new Typecho_Widget_Helper_Form_Element_Text('yc_key', NULL, NULL, _t('应用 KEY'), '啦啦啦啦');
28+
$form->addInput($yc_key);
29+
30+
$yc_input = new Typecho_Widget_Helper_Form_Element_Radio('yc_input', array('1' => '', '0' => ''), '0', '是否关闭传统登陆', '关闭后仅能使用扫码登陆。');
31+
$form->addInput($yc_input);
32+
33+
$yc_request = new Typecho_Widget_Helper_Form_Element_Text('yc_request', NULL, '5', _t('验证频率'), '请求洋葱服务器的频率,如果你不明白这是什么,请不要修改。');
34+
$yc_request->input->setAttribute('class', 'mini');
35+
$yc_request->addRule('isInteger','你不填写数字让我怎么办?实在搞不明白你就写个 5 得了。');
36+
$form->addInput($yc_request);
37+
38+
$yc_auth_type = new Typecho_Widget_Helper_Form_Element_Radio('yc_auth_type', array('1' => '确认按钮', '2' => '手势密码', '3' => '人脸', '4' => '声纹'), '1', '验证方式', '扫码成功后确认操作使用的验证方式');
39+
$form->addInput($yc_auth_type);
40+
}
41+
42+
public static function personalConfig(Typecho_Widget_Helper_Form $form){}
43+
44+
public static function js_header($str) {
45+
$str .= '<style type="text/css">
46+
.tab_panel, .typecho-login form{display: none}
47+
#tab_qrcode{padding-bottom: 1em; text-align: center}
48+
#tab_qrcode span{height: 100%; display: inline-block; vertical-align: middle}
49+
#tab_qrcode img, .bind_qrcode img{height: 280px; width: 280px; vertical-align: middle;cursor:pointer}
50+
#tab_qrcode img{margin-top: 1em}
51+
.bind_qrcode{display:none}
52+
</style>';
53+
echo $str;
54+
}
55+
56+
public static function js_profile($str) {
57+
$settings = Helper::options()->plugin('YangCong');
58+
$str .= '<script type="text/javascript">';
59+
$str .= 'jQuery(function($) {
60+
var bindTxt = \'<p class="bind_status">绑定状态:<span>未绑定</span></p><p class="bind_qrcode"><img src="" /></p>\';
61+
$("div.typecho-page-main div:first").append(bindTxt);
62+
var timer = null;
63+
64+
$(".bind_qrcode img").click(function(){
65+
$.getJSON("' . Helper::security()->getIndex('/action/YangCong?do=bind') . '", function(data){
66+
if(!data){
67+
$(".bind_status span").html("已绑定");
68+
$(".bind_qrcode").remove();
69+
} else if(data && data.status == 200){
70+
$(".bind_status span").html("未绑定");
71+
$(".bind_qrcode").show().find("img").attr("src", data.qrcode_url);
72+
timer = window.clearInterval(timer);
73+
timer = window.setInterval(function(){auth(data.event_id)},' . ($settings->yc_request * 1000) . ');
74+
}
75+
});
76+
}).click();
77+
78+
auth = function(event_id){
79+
$.getJSON("' . Helper::security()->getIndex('/action/YangCong?do=auth') . '", {event_id : event_id, action : "bind"}, function(data){
80+
if(data.status == 200){
81+
timer = window.clearInterval(timer);
82+
$(".bind_status span").html("绑定成功");
83+
$(".bind_qrcode").remove();
84+
}
85+
});
86+
}
87+
});';
88+
$str .= '</script>';
89+
echo $str;
90+
}
91+
92+
public static function js_login($str) {
93+
$settings = Helper::options()->plugin('YangCong');
94+
$str .= '<script type="text/javascript">';
95+
$str .= 'jQuery(function($) {
96+
$("form[name=login]").wrap(\'<div id="tab_account" class="tab_panel"></div>\');
97+
var tab = \'<ul class="typecho-option-tabs clearfix">\';
98+
tab += \'<li class="w-50 active"><a href="#tab_qrcode">扫码登陆</a></li>\';';
99+
if($settings->yc_input){
100+
//$str .= '$("div.login_account").remove();';
101+
} else {
102+
$str .= 'tab += \'<li class="w-50"><a href="#tab_account">传统登陆</a></li>\';';
103+
$str .= '$(".typecho-login form").show();';
104+
}
105+
$str .= 'tab += \'</ul>\';
106+
$("div.typecho-login h1").after(tab);
107+
$("p.more-link").before(\'<div id="tab_qrcode" class="tab_panel"><span></span><img src="" /></div>\');
108+
$("ul.typecho-option-tabs li a").click(function(){
109+
$("ul.typecho-option-tabs li").removeClass("active");
110+
$("div.tab_panel").hide();
111+
$(this).parent("li").addClass("active");
112+
$($(this).attr("href")).show();
113+
});
114+
$("#tab_qrcode").show();
115+
116+
var timer = null;
117+
$("#tab_qrcode img").click(function(){
118+
$.getJSON("' . Helper::security()->getIndex('/action/YangCong?do=login') . '", function(data){
119+
if(data.status == 200){
120+
$("#tab_qrcode img").attr("src", data.qrcode_url);
121+
timer = window.clearInterval(timer);
122+
timer = window.setInterval(function(){auth(data.event_id)},' . ($settings->yc_request * 1000) . ');
123+
}
124+
});
125+
}).click();
126+
127+
auth = function(event_id){
128+
$.getJSON("' . Helper::security()->getIndex('/action/YangCong?do=auth') . '", {event_id : event_id, action : "login"}, function(data){
129+
if(data.status == 200){
130+
timer = window.clearInterval(timer);
131+
window.location.href = data.redirect;
132+
}
133+
});
134+
}
135+
});';
136+
$str .= '</script>';
137+
echo $str;
138+
}
139+
}

YangCong/README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## 插件说明 ##
2+
3+
- 版本: v0.1.0
4+
- 作者: [冰剑](https://github.com/binjoo)
5+
- 主页: <https://github.com/binjoo/YangCong>
6+
7+
此插件涉及数据库操作,有潜在的未知风险,请慎用!
8+
9+
## 插件特点 ##
10+
11+
- [x] 扫码登陆(可选是否保留传统登陆方式)
12+
- [x] 四种验证方式(确认按钮、手势密码、人脸、声纹)
13+
- [ ] 超时提醒
14+
15+
## 使用方法 ##
16+
17+
1. 下载插件,将插件上传到 /usr/plugins/ 这个目录下
18+
2. 手机下载`洋葱APP`<https://www.yangcong.com/Download/APP>
19+
3. 登陆后台,在“控制台”下拉菜单中进入“插件管理”,启用当前插件
20+
4. 在“控制台”下拉菜单中进入“个人设置”,左侧二维码进行帐户绑定
21+
5. 后台右上角,退出登陆,然后在登录页使用`洋葱APP`扫码登陆
22+
23+
## 更新记录 ##
24+
25+
#### v0.1.0
26+
- 个人设置绑定帐户;
27+
- 插件设置四种验证方式;
28+
- 插件设置是否保留传统登陆方式;

0 commit comments

Comments
 (0)