前言
大卫科技 Blog原创作品,版权属于:大卫科技 Blog(转载请著名出处)!
原文链接https://www.iyuu.cn/archives/88/
如需转载,可下载Markdown原文:点此下载md.txt
本插件已部署,欢迎体验:
一、功能介绍
特色亮点功能:同一用户,可以绑定15种不同的登录方式!
在原项目TeConnect的基础上,进行完全的二次开发、优化及修复。重点有:
- 重新设计数据表结构,删除原connect表,后续具有完美的扩展性及兼容性;
- 已开发支持15种第三方登录,后续可以支持更多……;
- 优化会员绑定逻辑,修复原项目登录状态下绑定错乱、重复绑定等Bug;
- 增加会员uuid机制,自动关联users数据表的uid字段,支持更多功能开发的可能;
- 优化解绑逻辑,和第三方资料更新逻辑等。
项目仓库
码云:https://gitee.com/ledc/TeConnect
github:https://github.com/ledccn/TeConnect
二、插件下载
样式1 | 样式2 | 样式3 | 样式4 | 样式5 |
---|---|---|---|---|
三、安装步骤 即可查看!
- 解压插件到
Plugins
目录; - 在后台启用插件,并配置插件参数(方法见:参数配置 - 配置示例);
在当前使用主题的适当位置添加
TeConnect_Plugin::show()
方法,代码:<?php TeConnect_Plugin::show(); ?>
handsome Theme
示例图:
下载你喜欢的png登录图标,放到/usr/plugins/TeConnect/login_ico/{type}.png
,然后修改登录按钮样式在Plugin.php 第125行
,代码:<a href="{url}"><img src="/usr/plugins/TeConnect/login_ico/{type}.png" alt="{type}-{title}" style="margin-top: 0.8em;"></a>
- 在第三方平台设置网站回调域,
注意区分http、https
及地址重写隐藏index.php
(方法见:参数配置 - 配置示例)。 如果您的主题开启了全站PJAX,需要把以下代码放入PJAX回调函数内:
var exdate = new Date(); exdate.setDate(exdate.getDate() + 1); document.cookie = "TeConnect_Referer=" + encodeURI(window.location.href) + "; expires=" + exdate.toGMTString() + "; path=/";
四、参数配置
配置示例
1:后台互联配置
具体格式为:type:appid,appkey,title
,注释:
- type:第三方登录帐号类型
- appid:第三方开放平台申请的应用id
- appkey:第三方开放平台申请的应用key
- title:登录按钮的标题
在后台互联配置中,直接以文本形式填写,一行为一个帐号系统的参数;
为减少错误发生,您可以复制对应的配置示例
,把APP_KEY
和APP_SECRET
改成您自己的参数就可以了!
例如:qq:APP_KEY,APP_SECRET,腾讯QQ
改成:qq:101015836,547s87f8s7df7sd877ji75s78sdfd,腾讯QQ
粘贴到后台互联配置
,即完成了腾讯QQ登录的配置,其他类型同理!
2:网站回调域配置 即可查看
五、第三方账号绑定流程
1、方案选择
我参考了国内主流的几家互联网公司的第三方账号登录功能,发现主要分成两种设计方案;
一种是账号强绑,像京东、小米等,在第三方账号授权通过后,需要用户绑定自己的账号;
一种是今日头条、知乎,在第三方账号授权通过后,随机给用户生成一个账号或者调用第三方账号昵称,无需绑定账号,即可成功登录。
目前,两种方案都支持
,您可以在后台开启或关闭强制绑定
!
2、绑定流程一(未登录状态)
用户在登录界面点击第三方账号,授权通过后,我们获得用户第三方账号的OpenID,由此判断用户的第三方账号之前是否绑定过,如果绑定过则直接登录成功。
如果没有绑定过,则跳到账号绑定页面。账号绑定页面需要分成已有账号直接绑定,和没有账号,新注册账号进行绑定两种情况。
当用户已有账号时,通过输入账号密码校验身份,校验通过后即可绑定成功/登录成功。
当用户没有账号时,用户可通过注册新账号,注册成功后即可绑定成功/登录成功。
3、绑定流程二(登录状态)
在个人账号中心里提供绑定管理的功能和界面,在用户已经登录的情况下,可以直接绑定第三方账号,只要获得授权通过,即可绑定成功。
六、第三方帐号解绑流程
在个人账号中心>绑定管理中,可以对已经绑定的第三方账号进行解绑操作。在这里需要注意,由于用户长期使用第三方账号登录,实际上是由第三方账号承担了提交账号和保护账号安全的工作,因此在解绑第三方账号时,我们需要提醒用户,解绑以后只能通过本平台账号密码方式来登录。最好是提示用户记住当前账号
京东的解绑账号功能
另一方面,由于之前是由第三方账号“帮平台”做了账号安全的工作,因此在解绑账号的时候,我们需要考虑如何保护账号安全。因此可以在解绑的时候,对账号做一定的安全校验或安全保护。
我们最终定的方案是 当用户在解绑时,需要校验手机短信验证码,如果没有绑定手机,则提示用户先去绑定手机。
解绑流程
第三方账号虽然是一个小功能,但是在设计过程中,我们要结合自身产品的特点来确定产品方案和产品流程。授权之后,是直接登录成功,还是绑定自己平台的账号,这是由自己产品特点决定。同时,对新增账号来说,如何设计用户账号的安全,也需要根据产品特点和安全策略来设计适合的产品流程。
七、数据表结构(不开发,可以不看)
typecho_oauth_user数据库表结构:
字段 | 类型 | 注释 |
---|---|---|
uid | int(10) unsigned NOT NULL COMMENT | 用户ID |
access_token | varchar(255) NOT NULL COMMENT | 用户对应access_token |
datetime | timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT | 最后登录 |
expires_in | int(10) unsigned NOT NULL DEFAULT '0' COMMENT | access_token过期时间戳 |
gender | tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT | 性别0未知,1男,2女 |
head_img | varchar(255) NOT NULL COMMENT | 头像 |
name | varchar(38) NOT NULL COMMENT | 名字 |
nickname | varchar(38) NOT NULL COMMENT | 第三方昵称 |
openid | char(50) NOT NULL COMMENT | 第三方平台的用户唯一标识 |
refresh_token | varchar(255) NOT NULL COMMENT | 刷新有效期token |
type | char(32) NOT NULL COMMENT | 第三方平台的类型 |
uuid | int(10) unsigned NOT NULL COMMENT | 对应users表uid |
【推荐:后台关闭强制绑定】
- 管理员已登录状态时,直接互联登录,可以绑定管理员身份!(
源码第128行
此时users
表不变,oauth_user
表创建绑定关系,uid、uuid等于管理员uid); - 管理员未登录时,直接互联登录(
源码第153行
此时users
表创建新用户、oauth_user
表绑定关系:uid、uuid等于新用户uid); - 在第2步完成后,退出互联登录;重新用管理员登录成功后不退出,再次互联登录(
源码第256行
此时users
表不变,oauth_user
表更新绑定关系:uuid不变、uid等于管理员uid); - 同一用户,可以绑定15种不同的登录方式!但是,同类型的第三方账号仅可绑定一个!通俗点:用户不能绑定2个QQ号码来进行登录。(源码
250
行、267行
) oauth_user
表完整保存用户的关键授权参数access_token、expires_in、datetime,可以在用户离线的情况下调用API;- uuid完整记录着原始绑定关系,支持解绑后数据不丢失。
关键代码
/**
* 获取Oauth登录地址,重定向
*
* @access public
* @param string $type 第三方登录类型
*/
public function oauth(){
$type = $this->request->get('type');
if(is_null($type)){
throw new Typecho_Widget_Exception("请选择登录方式!");
}
$options = TeConnect_Plugin::options();
$type = strtolower($type);
//判断登录方式是否支持
if(!isset($options[$type])){
throw new Typecho_Widget_Exception("暂不支持该登录方式! {$type}");
}
//组装回调地址
$callback_url = Typecho_Common::url('/oauth_callback?type='.$type, $this->options->index);
//加载ThinkOauth类并实例化一个对象
require_once 'ThinkOauth.php';
$sdk = ThinkOauth::getInstance($type);
//302重定向
$this->response->redirect($sdk->getRequestCodeURL($callback_url));
}
/**
* 第三方登录回调
*
* @access public
* @param array $do POST来的用户绑定数据
* @param string $type 第三方登录类型
*/
public function callback(){
if(!isset($_SESSION)){
session_start();
$this->auth = isset($_SESSION['__typecho_auth']) ? $_SESSION['__typecho_auth'] : array();
$this->oauth_user = isset($_SESSION['__typecho_oauth_user']) ? $_SESSION['__typecho_oauth_user'] : array();
}
//仅处理来自绑定界面POST提交的数据,第三方回调会跳过
if($this->request->isPost()){
$do = $this->request->get('do');
if(!in_array($do,array('bind','reg'))){
throw new Typecho_Widget_Exception("错误数据!");
}
if(!isset($this->auth['openid']) || !isset($this->auth['type'])){
$this->response->redirect($this->options->index);
}
$func = 'doCallback'.ucfirst($do);
$this->$func();
unset($_SESSION['__typecho_auth']);
$this->response->redirect($this->options->index);
}
//第三方登录回调处理
$options = TeConnect_Plugin::options();
if(empty($this->auth)){
$this->auth['code'] = $this->request->get('code','');
$this->auth['type'] = $this->request->get('type','');
if(empty($this->auth['code']) && empty($this->auth['type']) && !isset($options[$this->auth['type']])){
//缺少code、type、type未开启,直接跳主页
$this->response->redirect($this->options->index);
}
//转小写
$this->auth['type'] = $type = strtolower($this->auth['type']);
//组装回调地址
$callback_url = Typecho_Common::url('/oauth_callback?type='.$type, $this->options->index);
//加载ThinkOauth类并实例化一个对象
require_once 'ThinkOauth.php';
$sdk = ThinkOauth::getInstance($type);
//请求接口(返回值包含openid)
$token = $sdk->getAccessToken($callback_url, $this->auth['code']);
if(is_array($token)){
//获取第三方账号数据
$user_info = $this->$type($token);
$oauth_user = array(
'uid'=>0,
'access_token'=>$token['access_token'],
'expires_in'=>isset($token['expires_in']) ? $this->options->gmtTime+$token['expires_in']: 0,
'gender'=>$user_info['gender'],
'head_img'=>$user_info['head_img'],
'name'=>$user_info['name'],
'nickname'=>$user_info['nickname'],
'openid'=>$token['openid'],
'type'=>$type,
);
//获取openid
$this->auth['openid'] = $token['openid'];
$this->auth['nickname'] = $user_info['nickname'];
}else{
$this->response->redirect($this->options->index);
}
}
//登录状态
if ($this->user->hasLogin()) {
//UUID会员的原始ID
$this->auth['uuid'] = $this->user->uid;
//直接绑定第三方账号
$this->bindUser($this->user->uid, $oauth_user, $this->auth['type']);
//提示,并跳转
$this->widget('Widget_Notice')->set(array('成功绑定账号!'));
$this->response->redirect($this->options->index);
}
//未登录状态,查询第三方账号的绑定关系
$isConnect = $this->findConnectUser($oauth_user,$this->auth['type']);
if($isConnect){
//已经绑定,直接登录
$this->useUidLogin($isConnect['uid']);
//提示,并跳转
$this->widget('Widget_Notice')->set(array('已成功登陆!'));
$this->response->redirect($this->options->index);
}
//未登录状态且未绑定,控制显示绑定界面
$custom = $this->options->plugin('TeConnect')->custom;
if(!$custom && !empty($this->auth['nickname'])){
$dataStruct = array(
'screenName'=> $this->auth['nickname'],
'created' => $this->options->gmtTime,
'group' => 'subscriber'
);
//新注册账号
$uid = $this->regConnectUser($dataStruct,$oauth_user);
if($uid){
$this->widget('Widget_Notice')->set(array('已成功注册并登陆!'));
}else{
$this->widget('Widget_Notice')->set(array('注册用户失败!'),'error');
}
$this->response->redirect($this->options->index);
}else{
//用户绑定界面
if(!isset($_SESSION['__typecho_auth']))
$_SESSION['__typecho_auth'] = $this->auth;
$_SESSION['__typecho_oauth_user'] = $oauth_user;
//未绑定,引导用户到绑定界面
$this->render('callback.php');
}
}
//绑定已有用户
protected function doCallbackBind(){
$name = $this->request->get('name');
$password = $this->request->get('password');
if(empty($name) || empty($password)){
$this->widget('Widget_Notice')->set(array('帐号或密码不能为空!'),'error');
$this->response->goBack();
}
$isLogin = $this->user->login($name,$password);
if($isLogin){
//UUID会员的原始ID
$this->auth['uuid'] = $this->user->uid;
$this->widget('Widget_Notice')->set(array('已成功绑定并登陆!'));
$this->bindUser($this->user->uid,$this->oauth_user,$this->auth['type']);
}else{
$this->widget('Widget_Notice')->set(array('帐号或密码错误!'),'error');
$this->response->goBack();
}
}
//注册新用户
protected function doCallbackReg(){
$url = $this->request->get('url');
$validator = new Typecho_Validate();
$validator->addRule('mail', 'required', _t('必须填写电子邮箱'));
$validator->addRule('mail', array($this, 'mailExists'), _t('电子邮箱地址已经存在'));
$validator->addRule('mail', 'email', _t('电子邮箱格式错误'));
$validator->addRule('mail', 'maxLength', _t('电子邮箱最多包含200个字符'), 200);
$validator->addRule('screenName', 'required', _t('必须填写昵称'));
$validator->addRule('screenName', 'xssCheck', _t('请不要在昵称中使用特殊字符'));
$validator->addRule('screenName', array($this, 'screenNameExists'), _t('昵称已经存在'));
if($url){
$validator->addRule('url', 'url', _t('个人主页地址格式错误'));
}
/** 截获验证异常 */
if ($error = $validator->run($this->request->from('mail', 'screenName', 'url'))) {
/** 设置提示信息 */
$this->widget('Widget_Notice')->set($error);
$this->response->goBack();
}
$dataStruct = array(
'mail' => $this->request->mail,
'screenName'=> $this->request->screenName,
'created' => $this->options->gmtTime,
'group' => 'subscriber'
);
$uid = $this->regConnectUser($dataStruct, $this->oauth_user);
if($uid){
$this->widget('Widget_Notice')->set(array('已成功注册并登陆!'));
}
}
protected function regConnectUser($data,$oauth_user){
$insertId = $this->insert($data);
if($insertId){
//UUID会员的原始ID
$this->auth['uuid'] = $insertId;
$this->bindUser($insertId,$oauth_user,$this->auth['type']);
$this->useUidLogin($insertId);
return $insertId;
}else{
return false;
}
}
//处理用户与第三方账号的绑定关系(逻辑复杂)
protected function bindUser($uid,$oauth_user,$type){
$oauth_user['uid'] = $uid;
if(isset($this->auth['uuid'])){
$oauth_user['uuid'] = $this->auth['uuid'];
}
//查询当前登录的账号是否绑定?
$connect = $this->db->fetchRow($this->db->select()
->from('table.oauth_user')
->where('uid = ?', $uid)
->where('type = ?', $type)
->limit(1));
if(empty($connect)){
//未绑定
$oauthRow = $this->findConnectUser($oauth_user,$type);
if($oauthRow){
//已存在第三方账号,更新绑定关系
$this->db->query($this->db
->update('table.oauth_user')
->rows(array('uid' => $uid))
->where('openid = ?', $oauth_user['openid'])
->where('type = ?', $type));
}else{
//未绑定,插入数据并绑定
$this->db->query($this->db->insert('table.oauth_user')->rows($oauth_user));
}
}else{
//已绑定,判断更新条件,避免绑定错乱(同类型的第三方账号,用户只能绑定一个)
if($connect[$type.'OpenId'] == $openid){
###更新资料tudo
}else{
###换绑tudo
}
}
}
//查找第三方账号
protected function findConnectUser($oauth_user,$type){
$user = $this->db->fetchRow($this->db->select()
->from('table.oauth_user')
->where('openid = ?', $oauth_user['openid'])
->where('type = ?', $type)
->limit(1));
return empty($user)? 0 : $user;
}
//使用用户uid登录
protected function useUidLogin($uid,$expire = 0){
$authCode = function_exists('openssl_random_pseudo_bytes') ?
bin2hex(openssl_random_pseudo_bytes(16)) : sha1(Typecho_Common::randString(20));
$user = array('uid'=>$uid,'authCode'=>$authCode);
Typecho_Cookie::set('__typecho_uid', $uid, $expire);
Typecho_Cookie::set('__typecho_authCode', Typecho_Common::hash($authCode), $expire);
//更新最后登录时间以及验证码
$this->db->query($this->db
->update('table.users')
->expression('logged', 'activated')
->rows(array('authCode' => $authCode))
->where('uid = ?', $uid));
$this->db->query($this->db
->update('table.oauth_user')
->rows(array('datetime' => date("Y-m-d H:i:s",time())))
->where('uid = ?', $uid));
}
public function render($themeFile){
/** 文件不存在 */
if (!file_exists($this->_themeDir . $themeFile)) {
Typecho_Common::error(500);
}
/** 输出模板 */
require_once $this->_themeDir . $themeFile;
}
/**
* 获取主题文件
*
* @access public
* @param string $fileName 主题文件
* @return void
*/
public function need($fileName){
require $this->_themeDir . $fileName;
}
//登录成功,获取腾讯QQ用户信息
public function qq($token){
$qq = ThinkOauth::getInstance('qq', $token);
$data = $qq->call('user/get_user_info');
if($data['ret'] == 0){
$userInfo['name'] = $data['nickname'];
$userInfo['nickname'] = $data['nickname'];
$userInfo['head_img'] = $data['figureurl_2'];
if($data['gender'] == '男'){
$userInfo['gender'] = 1;
}elseif($data['gender'] == '女'){
$userInfo['gender'] = 2;
}else{
$userInfo['gender'] = 0;
}
return $userInfo;
} else {
$this->widget('Widget_Notice')->set(array("获取腾讯QQ用户信息失败:{$data['msg']}"),'error');
}
}
//登录成功,获取腾讯微博用户信息
public function tencent($token){
$tencent = ThinkOauth::getInstance('tencent', $token);
$data = $tencent->call('user/info');
if($data['ret'] == 0){
$userInfo['name'] = $data['data']['name'];
$userInfo['nickname'] = $data['data']['nick'];
$userInfo['head_img'] = $data['data']['head'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取腾讯微博用户信息失败:{$data['msg']}");
}
}
//登录成功,获取新浪微博用户信息
public function sina($token){
$sina = ThinkOauth::getInstance('sina', $token);
$data = $sina->call('users/show', "uid={$sina->openid()}");
if($data['error_code'] == 0){
$userInfo['name'] = $data['name'];
$userInfo['nickname'] = $data['screen_name'];
$userInfo['head_img'] = $data['avatar_large'];
return $userInfo;
} else {
//throw_exception("获取新浪微博用户信息失败:{$data['error']}");
}
}
//登录成功,获取网易微博用户信息
public function t163($token){
$t163 = ThinkOauth::getInstance('t163', $token);
$data = $t163->call('users/show');
if($data['error_code'] == 0){
$userInfo['name'] = $data['name'];
$userInfo['nickname'] = $data['screen_name'];
$userInfo['head_img'] = str_replace('w=48&h=48', 'w=180&h=180', $data['profile_image_url']);
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取网易微博用户信息失败:{$data['error']}");
}
}
//登录成功,获取人人网用户信息
public function renren($token){
$renren = ThinkOauth::getInstance('renren', $token);
$data = $renren->call('user/get');
if(!isset($data['error'])){
$userInfo['name'] = $data['response']['name'];
$userInfo['nickname'] = $data['response']['name'];
$userInfo['head_img'] = $data['response']['avatar'][20]['url'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取人人网用户信息失败:{$data['error_msg']}");
}
}
//登录成功,获取360用户信息
public function x360($token){
$x360 = ThinkOauth::getInstance('x360', $token);
$data = $x360->call('user/me');
if($data['error_code'] == 0){
$userInfo['name'] = $data['name'];
$userInfo['nickname'] = $data['name'];
$userInfo['head_img'] = $data['avatar'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取360用户信息失败:{$data['error']}");
}
}
//登录成功,获取豆瓣用户信息
public function douban($token){
$douban = ThinkOauth::getInstance('douban', $token);
$data = $douban->call('user/~me');
if(empty($data['code'])){
$userInfo['name'] = $data['name'];
$userInfo['nickname'] = $data['name'];
$userInfo['head_img'] = $data['avatar'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取豆瓣用户信息失败:{$data['msg']}");
}
}
//登录成功,获取Github用户信息
public function github($token){
$github = ThinkOauth::getInstance('github', $token);
$data = $github->call('user');
if(empty($data['code'])){
$userInfo['name'] = $data['login'];
$userInfo['nickname'] = $data['name'];
$userInfo['head_img'] = $data['avatar_url'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取Github用户信息失败:{$data}");
}
}
//登录成功,获取Google用户信息
public function google($token){
$google = ThinkOauth::getInstance('google', $token);
$data = $google->call('userinfo');
if(!empty($data['id'])){
$userInfo['name'] = $data['name'];
$userInfo['nickname'] = $data['name'];
$userInfo['head_img'] = $data['picture'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取Google用户信息失败:{$data}");
}
}
//登录成功,获取msn用户信息
public function msn($token){
$msn = ThinkOauth::getInstance('msn', $token);
$data = $msn->call('me');
if(!empty($data['id'])){
$userInfo['name'] = $data['name'];
$userInfo['nickname'] = $data['name'];
$userInfo['head_img'] = '微软暂未提供头像URL,请通过 me/picture 接口下载';
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取msn用户信息失败:{$data}");
}
}
//登录成功,获取点点用户信息
public function diandian($token){
$diandian = ThinkOauth::getInstance('diandian', $token);
$data = $diandian->call('user/info');
if(!empty($data['meta']['status']) && $data['meta']['status'] == 200){
$userInfo['name'] = $data['response']['name'];
$userInfo['nickname'] = $data['response']['name'];
$userInfo['head_img'] = "https://api.diandian.com/v1/blog/{$data['response']['blogs'][0]['blogUuid']}/avatar/144";
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取点点用户信息失败:{$data}");
}
}
//登录成功,获取淘宝网用户信息
public function taobao($token){
$taobao = ThinkOauth::getInstance('taobao', $token);
$fields = 'user_id,nick,sex,buyer_credit,avatar,has_shop,vip_info';
$data = $taobao->call('taobao.user.buyer.get', "fields={$fields}");
if(!empty($data['user_buyer_get_response']['user'])){
$user = $data['user_buyer_get_response']['user'];
$userInfo['name'] = $user['user_id'];
$userInfo['nickname'] = $user['nick'];
$userInfo['head_img'] = $user['avatar'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取淘宝网用户信息失败:{$data['error_response']['msg']}");
}
}
//登录成功,获取百度用户信息
public function baidu($token){
$baidu = ThinkOauth::getInstance('baidu', $token);
$data = $baidu->call('passport/users/getLoggedInUser');
if(!empty($data['uid'])){
$userInfo['name'] = $data['uid'];
$userInfo['nickname'] = $data['uname'];
$userInfo['head_img'] = "http://tb.himg.baidu.com/sys/portrait/item/{$data['portrait']}";
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取百度用户信息失败:{$data['error_msg']}");
}
}
//登录成功,获取开心网用户信息
public function kaixin($token){
$kaixin = ThinkOauth::getInstance('kaixin', $token);
$data = $kaixin->call('users/me');
if(!empty($data['uid'])){
$userInfo['name'] = $data['uid'];
$userInfo['nickname'] = $data['name'];
$userInfo['head_img'] = $data['logo50'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取开心网用户信息失败:{$data['error']}");
}
}
//登录成功,获取搜狐用户信息
public function sohu($token){
$sohu = ThinkOauth::getInstance('sohu', $token);
$data = $sohu->call('user/get_info');
if('success' == $data['message'] && !empty($data['data'])){
$userInfo['name'] = $data['data']['open_id'];
$userInfo['nickname'] = $data['data']['nick'];
$userInfo['head_img'] = $data['data']['icon'];
$userInfo['gender'] = 0;
return $userInfo;
} else {
//throw_exception("获取搜狐用户信息失败:{$data['message']}");
}
}
本插件已部署,欢迎体验:
版权属于:大卫科技Blog
本文链接:https://www.iyuu.cn/archives/88/
转载时须注明出处
启动插件时跳转500
现在还能用吗?你站的QQ登录出现警告页面了,没更新了吗?
每一个网站申请一个API?
不小心点了禁用插件,再次开启;再次qq登录,用户还是需要重新绑定
500错误把表里值允许为NULL就好了,或者加个默认值,再或者去改mysql配置文件
最新的github上已修复。
Plugin.php on line 60
之前一直用着好好的,今天提示需要配置回调地址。以为腾讯互联出了问题,上去看了也没有变化,应该如何解决
学习一下
老大,为啥QQ登录后不像本站一样能获取QQ昵称呢,全是空白资料,如果开启登录完善资料,填写后点击确定不跳转
登录成功后如何隐藏按钮?
路过,大佬66666
学习一下,冒个泡
大佬牛逼
还不错
500错误解决方案:修改typecho_oauth_user表,加上默认值即可
最新的github上已修复。
致命错误是这个:SQLSTATE[HY000]: General error: 1364 Field 'access_token' doesn't have a default value
QQ登录报错:Notice: Undefined variable: oauth_user in D:\htdocs\usr\plugins\TeConnect\Widget.php on line 135
Server Error
最新的github上已修复。
看看,说不定能用到。
看起来很不错的插件~
不错!顶~
前来体验
大佬审核一下呀~ 想用这个插件~
我安装了回调地址打开显示错误Argument 1 passed to themeInit() must be an instance of Widget_Archive, instance of TeConnect_Widget given, called in /www/wwwroot/usr/plugins/TeConnect/Widget.php on line 24
安装步骤第一步,仔细看看。
这么好的东西一定要顶一下!
|´・ω・)ノ
谢谢分享
体验下
学习一下~
|´・ω・)ノ
能和LoveKKVIP 共同使用吗?
有没有卸载方法,
大佬,微信公众号授权登录可以安排上吗
试试看 貌似没头像
测试
୧(๑•̀⌄•́๑)૭
学习一下
登陆跳转显示500,Server Error
看了一下日志:
[Fri Nov 15 15:32:56.257195 2019] [proxy_fcgi:error] [pid 1379:tid 139921167705856] [client 00000000:8811] AH01071: Got error 'PHP message: PHP Notice: Undefined variable: oauth_user in /data/wwwroot/rplib.cn/usr/plugins/TeConnect/Widget.php on line 135', referer: https://rplib.cn/admin/login.php
最新的github上已修复。
我也来学习学习下OωO
体验完毕,滴!访客卡!请上车的乘客系好安全带,现在是:Tue Nov 12 2019 13:29:27 GMT+0800 (中国标准时间)
滴!访客卡!请上车的乘客系好安全带,现在是:Tue Nov 12 2019 13:29:27 GMT+0800 (中国标准时间)
我登录出现了错误数据,链接https://blog.xiaohongyan.cn
帮我看看
解决了,但是用qq登录后跳转,没显示已经登录。还是处于游客状态
看了半天才发现要评论才有步骤
大佬开发版的typecho绑定账号和注册都是直接跳首页变成未登录了
博主,我这边发现一个问题,就是qq注册的用户,后台删除了,就再也不能qq登录注册了,怎么修复?
有2个表。另一个表,也删除。
小白表示完全看不懂
膜拜一下准备上车
小白表示完全看不懂
感谢分享。有一说一,QQ 提供的这几个样式都好丑
确实如是。
不行,严格按照上面的步骤去配置插件了,但是最后使用QQ登录的时候显示这个错误Database Query Error
请安装最新版本的,再试一下。
仔细检查配置是否出错。
微博登录同样出现Database Query Error,插件也按照你说的设置了
最新的github上已修复。
我的天,好棒呀
ヾ(≧∇≦*)ゝ
666
福娃福娃二分
感觉图标有点大。
需要多大的图标,可以去QQ官方下载源文件修改。
(●—●)拿走了
厉害了
不行哦,Database Query Error
nginx 500
不错,增加微信登陆就完美了
学习 想看隐藏文件
学习 想看隐藏文件
haha
顶一下
666
很强
我在QQ互联看到的是 APP ID:和APP Key:,APP_KEY,APP_SECRET在哪看啊 ,好像格式还不一样OωO
APP ID:和APP Key,是一样的意思。
test
|´・ω・)ノ先看一下隐藏内容
[...]https://www.iyuu.cn/archives/88/[...]
需要完善一下,就是登录后在哪个页面登录的就回到哪个页面,这样就更好了,比如登录后台,第三方登录后直接跳去首页,又要重新进后台,这样比较麻烦的
2020年8月3日19:10:00 功能已做好,推送至github。更新体验下吧!
这个功能可以有,抽空做一下。人性化很多。
666牛B哦!
我来了
看看
这个“适当位置”就很魔性了,整了半天愣是没整明白
每个模板登录按钮所在位置不一样。具体分析。
牛批
评论一下看下,评论一下看下
(๑•̀ㅁ•́ฅ)
留个记号
冒个泡
学习学习!
此贴留名记录。2019年8月11日
之前用TeConnect的怎么做数据迁移
我做个升级脚本,做好了放到本页面。
做了吗(´இ皿இ`)