更新第三方登录插件扩展
This commit is contained in:
@@ -13,26 +13,26 @@ namespace addons\syslogin;
|
||||
* @author thinkphp
|
||||
*/
|
||||
|
||||
class Plugin extends \sent\Addons{
|
||||
class Plugin extends \sent\Addons {
|
||||
|
||||
public $info = array(
|
||||
'name'=>'Syslogin',
|
||||
'title'=>'第三方登录',
|
||||
'description'=>'第三方登录',
|
||||
'status'=>1,
|
||||
'author'=>'molong',
|
||||
'version'=>'0.1'
|
||||
'name' => 'Syslogin',
|
||||
'title' => '第三方登录',
|
||||
'description' => '第三方登录',
|
||||
'status' => 1,
|
||||
'author' => 'molong',
|
||||
'version' => '0.1',
|
||||
);
|
||||
|
||||
public function loginBottomAddon(){
|
||||
public function loginBottomAddon() {
|
||||
return $this->fetch('login');
|
||||
}
|
||||
|
||||
public function install(){
|
||||
public function install() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function uninstall(){
|
||||
public function uninstall() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
6
addons/syslogin/config.php
Normal file
6
addons/syslogin/config.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
return [
|
||||
'qq' => ['title' => 'QQ', 'name' => 'qq', 'type' => 'fieldlist', 'value' => ['app_id' => '', 'app_secret' => '', 'callback' => '/', 'code' => '', 'scope' => '']],
|
||||
'wechat' => ['title' => 'Wechat', 'name' => 'wechat', 'type' => 'fieldlist', 'value' => ['app_id' => '', 'app_secret' => '', 'callback' => '/', 'scope' => '']],
|
||||
'weibo' => ['title' => 'Weibo', 'name' => 'weibo', 'type' => 'fieldlist', 'value' => ['app_id' => '', 'app_secret' => '', 'callback' => '/']],
|
||||
];
|
||||
@@ -9,12 +9,60 @@
|
||||
|
||||
namespace addons\syslogin\controller;
|
||||
|
||||
class Index extends \app\controller\front\Base{
|
||||
use addons\syslogin\model\SyncLogin;
|
||||
use think\facade\Session;
|
||||
|
||||
public function login(){
|
||||
}
|
||||
class Index extends \app\controller\front\Base {
|
||||
|
||||
public function callback(){
|
||||
public function login() {
|
||||
$config = $this->getAddonsConfig();
|
||||
foreach ($config as $key => $value) {
|
||||
$config[$key] = json_decode($value, true);
|
||||
}
|
||||
$app = new \addons\syslogin\service\Application($config);
|
||||
$platform = $this->request->param('platform');
|
||||
return $this->redirect($app->$platform->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
}
|
||||
public function callback() {
|
||||
$code = $this->request->param('code');
|
||||
if (!$code) {
|
||||
return $this->error("非法操作!");
|
||||
}
|
||||
$config = $this->getAddonsConfig();
|
||||
foreach ($config as $key => $value) {
|
||||
$config[$key] = json_decode($value, true);
|
||||
}
|
||||
$app = new \addons\syslogin\service\Application($config);
|
||||
$platform = $this->request->param('platform', 'wechat');
|
||||
$userInfo = $app->$platform->getUserInfo();
|
||||
|
||||
Session::set("{$platform}-userinfo", $userInfo);
|
||||
$sync = SyncLogin::where(['platform' => $platform, 'openid' => $userInfo['openid']])->find();
|
||||
if ($sync) {
|
||||
if ($sync['uid']) {
|
||||
//已绑定用户直接登录
|
||||
SyncLogin::login($userInfo);
|
||||
} else {
|
||||
//未绑定用户跳转绑定用户
|
||||
return $this->redirect('/addons/syslogin/index/bind/platform/' . $platform);
|
||||
}
|
||||
} else {
|
||||
SyncLogin::register($userInfo);
|
||||
//未绑定用户跳转绑定用户
|
||||
return $this->redirect('/addons/syslogin/index/bind/platform/' . $platform);
|
||||
}
|
||||
}
|
||||
|
||||
public function bind() {
|
||||
$platform = $this->request->param('platform', 'wechat');
|
||||
|
||||
$userinfo = Session::get("{$platform}-userinfo");
|
||||
|
||||
$this->data = [
|
||||
'userinfo' => $userinfo['userinfo'],
|
||||
'platform' => $platform,
|
||||
];
|
||||
return $this->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
16
addons/syslogin/model/SyncLogin.php
Normal file
16
addons/syslogin/model/SyncLogin.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace addons\syslogin\model;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class SyncLogin extends \think\model {
|
||||
|
||||
public static function login($user) {
|
||||
|
||||
}
|
||||
|
||||
public static function register($user) {
|
||||
|
||||
}
|
||||
}
|
||||
67
addons/syslogin/service/Application.php
Normal file
67
addons/syslogin/service/Application.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace addons\syslogin\service;
|
||||
|
||||
class Application {
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* 服务提供者
|
||||
* @var array
|
||||
*/
|
||||
private $providers = [
|
||||
'qq' => 'Qq',
|
||||
'weibo' => 'Weibo',
|
||||
'wechat' => 'Wechat',
|
||||
];
|
||||
|
||||
/**
|
||||
* 服务对象信息
|
||||
* @var array
|
||||
*/
|
||||
protected $services = [];
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
$options = array_intersect_key($options, $this->providers);
|
||||
$options = array_merge($this->config, is_array($options) ? $options : []);
|
||||
foreach ($options as $key => &$option) {
|
||||
$option['app_id'] = isset($option['app_id']) ? $option['app_id'] : '';
|
||||
$option['app_secret'] = isset($option['app_secret']) ? $option['app_secret'] : '';
|
||||
// 如果未定义回调地址则自动生成
|
||||
$option['callback'] = isset($option['callback']) && $option['callback'] ? $option['callback'] : addon_url('syslogin/index/callback', [':platform' => $key], false, true);
|
||||
}
|
||||
$this->config = $options;
|
||||
//注册服务器提供者
|
||||
$this->registerProviders();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册服务提供者
|
||||
*/
|
||||
private function registerProviders()
|
||||
{
|
||||
foreach ($this->providers as $k => $v) {
|
||||
$this->services[$k] = function () use ($k, $v) {
|
||||
$options = $this->config[$k];
|
||||
$objname = __NAMESPACE__ . "\\{$v}";
|
||||
return new $objname($options);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$this->services[$key] = $value;
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
{
|
||||
return isset($this->services[$key]) ? $this->services[$key]($this) : null;
|
||||
}
|
||||
}
|
||||
132
addons/syslogin/service/Qq.php
Normal file
132
addons/syslogin/service/Qq.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
namespace addons\syslogin\service;
|
||||
|
||||
use think\facade\Config;
|
||||
use think\facade\Session;
|
||||
|
||||
/**
|
||||
* QQ
|
||||
*/
|
||||
class Qq {
|
||||
const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";
|
||||
const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
|
||||
const GET_USERINFO_URL = "https://graph.qq.com/user/get_user_info";
|
||||
const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
public function __construct($options = []) {
|
||||
if ($config = Config::get('third.qq')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登陆
|
||||
*/
|
||||
public function login() {
|
||||
header("Location:" . $this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取authorize_url
|
||||
*/
|
||||
public function getAuthorizeUrl() {
|
||||
$state = md5(uniqid(rand(), true));
|
||||
Session::set('state', $state);
|
||||
$queryarr = array(
|
||||
"response_type" => "code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"scope" => $this->config['scope'],
|
||||
"state" => $state,
|
||||
);
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getUserInfo($params = []) {
|
||||
$params = $params ? $params : $_GET;
|
||||
if (isset($params['access_token']) || (isset($params['state']) && $params['state'] == Session::get('state') && isset($params['code']))) {
|
||||
//获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
$openid = $this->getOpenId($access_token);
|
||||
//获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
"oauth_consumer_key" => $this->config['app_id'],
|
||||
"openid" => $openid,
|
||||
];
|
||||
$ret = Http::get(self::GET_USERINFO_URL, $queryarr);
|
||||
$userinfo = (array) json_decode($ret, true);
|
||||
if (!$userinfo || !isset($userinfo['ret']) || $userinfo['ret'] !== 0) {
|
||||
return [];
|
||||
}
|
||||
$userinfo = $userinfo ? $userinfo : [];
|
||||
$userinfo['avatar'] = isset($userinfo['figureurl_qq_2']) ? $userinfo['figureurl_qq_2'] : '';
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'openid' => $openid,
|
||||
'userinfo' => $userinfo,
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '') {
|
||||
if (!$code) {
|
||||
return [];
|
||||
}
|
||||
$queryarr = array(
|
||||
"grant_type" => "authorization_code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"client_secret" => $this->config['app_secret'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"code" => $code,
|
||||
);
|
||||
$ret = Http::get(self::GET_ACCESS_TOKEN_URL, $queryarr);
|
||||
$params = [];
|
||||
parse_str($ret, $params);
|
||||
return $params ? $params : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取open_id
|
||||
* @param string $access_token
|
||||
* @return string
|
||||
*/
|
||||
private function getOpenId($access_token = '') {
|
||||
$response = Http::get(self::GET_OPENID_URL, ['access_token' => $access_token]);
|
||||
if (strpos($response, "callback") !== false) {
|
||||
$lpos = strpos($response, "(");
|
||||
$rpos = strrpos($response, ")");
|
||||
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
|
||||
}
|
||||
$user = (array) json_decode($response, true);
|
||||
return isset($user['openid']) ? $user['openid'] : '';
|
||||
}
|
||||
}
|
||||
87
addons/syslogin/service/Service.php
Normal file
87
addons/syslogin/service/Service.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
namespace addons\syslogin\service;
|
||||
|
||||
use addons\syslogin\model\Third;
|
||||
use app\model\Member as User;
|
||||
use think\exception\PDOException;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 第三方登录服务类
|
||||
*
|
||||
* @author Karson
|
||||
*/
|
||||
class Service {
|
||||
|
||||
/**
|
||||
* 第三方登录
|
||||
* @param string $platform 平台
|
||||
* @param array $params 参数
|
||||
* @param array $extend 会员扩展信息
|
||||
* @param int $keeptime 有效时长
|
||||
* @return boolean
|
||||
*/
|
||||
public static function connect($platform, $params = [], $extend = [], $keeptime = 0) {
|
||||
$time = time();
|
||||
$values = [
|
||||
'platform' => $platform,
|
||||
'openid' => $params['openid'],
|
||||
'openname' => isset($params['userinfo']['nickname']) ? $params['userinfo']['nickname'] : '',
|
||||
'access_token' => $params['access_token'],
|
||||
'refresh_token' => $params['refresh_token'],
|
||||
'expires_in' => $params['expires_in'],
|
||||
'logintime' => $time,
|
||||
'expiretime' => $time + $params['expires_in'],
|
||||
];
|
||||
$auth = \app\common\library\Auth::instance();
|
||||
|
||||
$auth->keeptime($keeptime);
|
||||
$third = Third::get(['platform' => $platform, 'openid' => $params['openid']]);
|
||||
if ($third) {
|
||||
$user = User::get($third['user_id']);
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
$third->save($values);
|
||||
return $auth->direct($user->id);
|
||||
} else {
|
||||
// 先随机一个用户名,随后再变更为u+数字id
|
||||
$username = Random::alnum(20);
|
||||
$password = Random::alnum(6);
|
||||
$domain = request()->host();
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
// 默认注册一个会员
|
||||
$result = $auth->register($username, $password, $username . '@' . $domain, '', $extend, $keeptime);
|
||||
if (!$result) {
|
||||
return false;
|
||||
}
|
||||
$user = $auth->getUser();
|
||||
$fields = ['username' => 'u' . $user->id, 'email' => 'u' . $user->id . '@' . $domain];
|
||||
if (isset($params['userinfo']['nickname'])) {
|
||||
$fields['nickname'] = $params['userinfo']['nickname'];
|
||||
}
|
||||
if (isset($params['userinfo']['avatar'])) {
|
||||
$fields['avatar'] = htmlspecialchars(strip_tags($params['userinfo']['avatar']));
|
||||
}
|
||||
|
||||
// 更新会员资料
|
||||
$user = User::get($user->id);
|
||||
$user->save($fields);
|
||||
|
||||
// 保存第三方信息
|
||||
$values['user_id'] = $user->id;
|
||||
Third::create($values);
|
||||
Db::commit();
|
||||
} catch (PDOException $e) {
|
||||
Db::rollback();
|
||||
$auth->logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 写入登录Cookies和Token
|
||||
return $auth->direct($user->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
122
addons/syslogin/service/Wechat.php
Normal file
122
addons/syslogin/service/Wechat.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace addons\syslogin\service;
|
||||
|
||||
use think\facade\Config;
|
||||
use think\facade\Session;
|
||||
|
||||
/**
|
||||
* 微信
|
||||
*/
|
||||
class Wechat {
|
||||
const GET_AUTH_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize";
|
||||
const GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
|
||||
const GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
public function __construct($options = []) {
|
||||
if ($config = Config::get('third.wechat')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登陆
|
||||
*/
|
||||
public function login() {
|
||||
header("Location:" . $this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取authorize_url
|
||||
*/
|
||||
public function getAuthorizeUrl() {
|
||||
$state = md5(uniqid(rand(), true));
|
||||
Session::set('state', $state);
|
||||
$queryarr = array(
|
||||
"appid" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"response_type" => "code",
|
||||
"scope" => $this->config['scope'],
|
||||
"state" => $state,
|
||||
);
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr) . '#wechat_redirect';
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getUserInfo($params = []) {
|
||||
$params = $params ? $params : request()->get();
|
||||
if (isset($params['access_token']) || (isset($params['state']) && $params['state'] == Session::get('state') && isset($params['code']))) {
|
||||
//获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
$openid = isset($data['openid']) ? $data['openid'] : '';
|
||||
$unionid = isset($data['unionid']) ? $data['unionid'] : '';
|
||||
if (stripos($this->config['scope'], 'snsapi_userinfo') !== false) {
|
||||
//获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
"openid" => $openid,
|
||||
"lang" => 'zh_CN',
|
||||
];
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$ret = $client->post(self::GET_USERINFO_URL, ['form_params' => $queryarr])->getBody()->getContents();
|
||||
$userinfo = (array) json_decode($ret, true);
|
||||
if (!$userinfo || isset($userinfo['errcode'])) {
|
||||
return [];
|
||||
}
|
||||
$userinfo = $userinfo ? $userinfo : [];
|
||||
$userinfo['avatar'] = isset($userinfo['headimgurl']) ? $userinfo['headimgurl'] : '';
|
||||
} else {
|
||||
$userinfo = [];
|
||||
}
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'openid' => $openid,
|
||||
'unionid' => $unionid,
|
||||
'userinfo' => $userinfo,
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '') {
|
||||
if (!$code) {
|
||||
return [];
|
||||
}
|
||||
$queryarr = array(
|
||||
"appid" => $this->config['app_id'],
|
||||
"secret" => $this->config['app_secret'],
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
);
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$response = $client->post(self::GET_ACCESS_TOKEN_URL, ['form_params' => $queryarr])->getBody()->getContents();
|
||||
$ret = (array) json_decode($response, true);
|
||||
return $ret ? $ret : [];
|
||||
}
|
||||
}
|
||||
114
addons/syslogin/service/Weibo.php
Normal file
114
addons/syslogin/service/Weibo.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace addons\syslogin\service;
|
||||
|
||||
use think\facade\Config;
|
||||
use think\facade\Session;
|
||||
|
||||
/**
|
||||
* 微博
|
||||
*/
|
||||
class Weibo {
|
||||
const GET_AUTH_CODE_URL = "https://api.weibo.com/oauth2/authorize";
|
||||
const GET_ACCESS_TOKEN_URL = "https://api.weibo.com/oauth2/access_token";
|
||||
const GET_USERINFO_URL = "https://api.weibo.com/2/users/show.json";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
public function __construct($options = []) {
|
||||
if ($config = Config::get('third.weibo')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登陆
|
||||
*/
|
||||
public function login() {
|
||||
header("Location:" . $this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取authorize_url
|
||||
*/
|
||||
public function getAuthorizeUrl() {
|
||||
$state = md5(uniqid(rand(), true));
|
||||
Session::set('state', $state);
|
||||
$queryarr = array(
|
||||
"response_type" => "code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"state" => $state,
|
||||
);
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getUserInfo($params = []) {
|
||||
$params = $params ? $params : $_GET;
|
||||
if (isset($params['access_token']) || (isset($params['state']) && $params['state'] == Session::get('state') && isset($params['code']))) {
|
||||
//获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
$uid = isset($data['uid']) ? $data['uid'] : '';
|
||||
//获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
"uid" => $uid,
|
||||
];
|
||||
$ret = Http::get(self::GET_USERINFO_URL, $queryarr);
|
||||
$userinfo = (array) json_decode($ret, true);
|
||||
if (!$userinfo || isset($userinfo['error_code'])) {
|
||||
return [];
|
||||
}
|
||||
$userinfo = $userinfo ? $userinfo : [];
|
||||
$userinfo['nickname'] = isset($userinfo['screen_name']) ? $userinfo['screen_name'] : '';
|
||||
$userinfo['avatar'] = isset($userinfo['profile_image_url']) ? $userinfo['profile_image_url'] : '';
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'openid' => $uid,
|
||||
'userinfo' => $userinfo,
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '') {
|
||||
if (!$code) {
|
||||
return '';
|
||||
}
|
||||
$queryarr = array(
|
||||
"grant_type" => "authorization_code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"client_secret" => $this->config['app_secret'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"code" => $code,
|
||||
);
|
||||
$response = Http::post(self::GET_ACCESS_TOKEN_URL, $queryarr);
|
||||
$ret = (array) json_decode($response, true);
|
||||
return $ret ? $ret : [];
|
||||
}
|
||||
}
|
||||
79
addons/syslogin/view/index/bind.html
Normal file
79
addons/syslogin/view/index/bind.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{extend name="../../../view/addon/front" /}
|
||||
{block name="body"}
|
||||
<div class="text-center">
|
||||
<img src="{$userinfo.avatar}" class="img-circle" width="80" height="80" alt=""/>
|
||||
<div style="margin-top:15px;">{$userinfo.nickname}</div>
|
||||
</div>
|
||||
<div class="user-section login-section nav-tabs-custom" style="margin-top:20px;">
|
||||
<ul class="logon-tab clearfix nav nav-tabs">
|
||||
<li class="active"><a href="#tab-login" data-toggle="tab">绑定已有账号</a></li>
|
||||
<li><a href="#tab-register" data-toggle="tab">创建新账号</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane tab-box fade in active bind-main login-main" id="tab-login">
|
||||
<form name="form" id="bind-form" class="form-vertical" method="POST" role="form">
|
||||
<input type="hidden" name="platform" value="{$platform}"/>
|
||||
<div class="form-group">
|
||||
<label class="control-label">账号</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="username" name="username" data-rule="required" class="form-control input-lg" placeholder="用户名">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">密码</label>
|
||||
<div class="controls">
|
||||
<input type="password" id="password" name="password" data-rule="required;password" class="form-control input-lg" placeholder="密码">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-block btn-lg">确认绑定</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane tab-box fade in register-main login-main" id="tab-register">
|
||||
<form name="form" id="register-form" class="form-vertical" method="POST" role="form">
|
||||
<input type="hidden" name="platform" value="{$platform}"/>
|
||||
<div class="form-group">
|
||||
<label class="control-label">邮箱</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="email" name="email" data-rule="required;email" class="form-control input-lg" placeholder="">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">用户名</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="username" name="username" data-rule="required;length(3~30, true)" class="form-control input-lg" placeholder="">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">密码</label>
|
||||
<div class="controls">
|
||||
<input type="password" id="password" name="password" data-rule="required;password" class="form-control input-lg" placeholder="">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">手机号码</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="mobile" name="mobile" data-rule="required;mobile" class="form-control input-lg" placeholder="">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-block btn-lg">创建账号并绑定</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
|
||||
<script>
|
||||
console.log('dd');
|
||||
</script>
|
||||
{/block}
|
||||
@@ -1 +0,0 @@
|
||||
登录
|
||||
@@ -3,6 +3,7 @@
|
||||
.third-login li{list-style: none;}
|
||||
</style>
|
||||
<ul class="third-login">
|
||||
<li><a href="{:addons_url('syslogin/index/login', ['type' => 'qq'])}"><i class="fa fa-qq"></i> QQ登录</a></li>
|
||||
<li><a href="{:addons_url('syslogin/index/login', ['type' => 'wechat'])}"><i class="fa fa-wechat"></i> 微信登录</a></li>
|
||||
<li><a href="{:addons_url('syslogin/index/login', ['platform' => 'qq'])}"><i class="fa fa-qq"></i> QQ登录</a></li>
|
||||
<li><a href="{:addons_url('syslogin/index/login', ['platform' => 'wechat'])}"><i class="fa fa-wechat"></i> 微信登录</a></li>
|
||||
<li><a href="{:addons_url('syslogin/index/login', ['platform' => 'weibo'])}"><i class="fa fa-weibo"></i> 微博登录</a></li>
|
||||
</ul>
|
||||
@@ -8,16 +8,15 @@
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\controller;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\View;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Route;
|
||||
use think\facade\Event;
|
||||
use think\Validate;
|
||||
use app\model\Config;
|
||||
use app\model\Hooks;
|
||||
use app\model\SeoRule;
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Event;
|
||||
use think\facade\View;
|
||||
use think\Validate;
|
||||
|
||||
class Base {
|
||||
|
||||
@@ -78,7 +77,7 @@ class Base {
|
||||
$hooks = Cache::get('sentcms_hooks');
|
||||
if (!$hooks) {
|
||||
$hooks = Hooks::where('status', 1)->column('addons', 'name');
|
||||
foreach($hooks as $key => $values){
|
||||
foreach ($hooks as $key => $values) {
|
||||
if (is_string($values)) {
|
||||
$values = explode(',', $values);
|
||||
} else {
|
||||
@@ -95,7 +94,6 @@ class Base {
|
||||
Event::listenEvents($hooks);
|
||||
}
|
||||
|
||||
|
||||
View::assign('version', \think\facade\Env::get('VERSION'));
|
||||
View::assign('config', $this->config);
|
||||
// 控制器初始化
|
||||
@@ -142,7 +140,7 @@ class Base {
|
||||
}
|
||||
|
||||
protected function fetch($template = '') {
|
||||
if($this->request->param('addon')){
|
||||
if ($this->request->param('addon')) {
|
||||
$this->tpl_config['view_dir_name'] = 'addons' . DIRECTORY_SEPARATOR . $this->request->param('addon') . DIRECTORY_SEPARATOR . 'view';
|
||||
}
|
||||
View::config($this->tpl_config);
|
||||
@@ -154,7 +152,8 @@ class Base {
|
||||
* 是否为手机访问
|
||||
* @return boolean [description]
|
||||
*/
|
||||
public function isMobile() {//return true;
|
||||
public function isMobile() {
|
||||
//return true;
|
||||
// 如果有HTTP_X_WAP_PROFILE则一定是移动设备
|
||||
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
|
||||
return true;
|
||||
@@ -200,14 +199,14 @@ class Base {
|
||||
if (class_exists($class)) {
|
||||
$reflection = new \ReflectionClass($class);
|
||||
$group_doc = $this->Parser($reflection->getDocComment());
|
||||
if(isset($group_doc['title'])){
|
||||
if (isset($group_doc['title'])) {
|
||||
$mate = $group_doc['title'];
|
||||
}
|
||||
$method = $reflection->getMethods(\ReflectionMethod::IS_FINAL | \ReflectionMethod::IS_PUBLIC);
|
||||
$method = $reflection->getMethods(\ReflectionMethod::IS_FINAL | \ReflectionMethod::IS_PUBLIC);
|
||||
foreach ($method as $key => $v) {
|
||||
if($action == $v->name){
|
||||
if ($action == $v->name) {
|
||||
$title_doc = $this->Parser($v->getDocComment());
|
||||
if(isset($title_doc['title'])){
|
||||
if (isset($title_doc['title'])) {
|
||||
$mate = $title_doc['title'];
|
||||
}
|
||||
}
|
||||
@@ -223,8 +222,8 @@ class Base {
|
||||
|
||||
protected function setSeo($title = '', $keywords = '', $description = '') {
|
||||
$seo = array(
|
||||
'title' => $title,
|
||||
'keywords' => $keywords,
|
||||
'title' => $title,
|
||||
'keywords' => $keywords,
|
||||
'description' => $description,
|
||||
);
|
||||
//获取还没有经过变量替换的META信息
|
||||
@@ -237,10 +236,19 @@ class Base {
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'title' => $meta['title'],
|
||||
'keywords' => $meta['keywords'],
|
||||
'title' => $meta['title'],
|
||||
'keywords' => $meta['keywords'],
|
||||
'description' => $meta['description'],
|
||||
);
|
||||
View::assign('seo', $data);
|
||||
}
|
||||
|
||||
protected function getAddonsConfig() {
|
||||
$config = [];
|
||||
$addons = $this->request->param('addon');
|
||||
$addon = get_addons_instance($addons)->getConfig();
|
||||
$config = \app\model\Addons::where('name', $addons)->value('config');
|
||||
|
||||
return $config ? json_decode($config, true) : $addon;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +138,9 @@ class Addons extends Base {
|
||||
|
||||
$keyList = $class->getConfig(true);
|
||||
$this->data = array(
|
||||
'info' => $info['config'],
|
||||
'keyList' => $keyList,
|
||||
'meta_title' => $info['title'] . " - 设置"
|
||||
'meta_title' => $info['title'] . " - 设置",
|
||||
);
|
||||
return $this->fetch('admin/public/edit');
|
||||
} else {
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
<dd>
|
||||
<a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> 追加</a>
|
||||
</dd>
|
||||
<textarea name="{$name}" class="form-control hide" cols="30" rows="5">{$value}</textarea>
|
||||
<textarea name="{$name}" class="form-control hide" cols="30" rows="5">{if is_string($value)}{$value}{else/}{:json_encode($value)}{/if}</textarea>
|
||||
</dl>
|
||||
@@ -101,9 +101,8 @@ class Model extends \think\Model{
|
||||
(new Attribute())->where('model_id', $data['id'])->delete();
|
||||
$db = new \com\Datatable();
|
||||
if ($db->CheckTable($data['name'])) {
|
||||
$result = $db->delTable($data['name'])->query();
|
||||
$db->delTable($data['name'])->query();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function setAttributeSortAttr($value) {
|
||||
|
||||
@@ -398,18 +398,16 @@ define(['jquery', 'bootstrap', 'validator'], function ($, undefined, Validator)
|
||||
return true;
|
||||
}
|
||||
var template = $(this).data("template");
|
||||
var json = [];
|
||||
var json = {};
|
||||
try {
|
||||
var d = textarea.val().split(/[\n,]/g);
|
||||
d.map(function(item, i){
|
||||
json.push(item.split(":"))
|
||||
})
|
||||
// json = JSON.parse(textarea.val());
|
||||
json = JSON.parse(textarea.val());
|
||||
} catch (e) {
|
||||
}
|
||||
$.each(json, function (i, j) {
|
||||
var item = (j.length > 0) ? {key:j[0],value:j[1],other:j[2]} : {key:i,value:j[0]};
|
||||
$(".btn-append,.append", container).trigger('click', template ? j : item);
|
||||
$(".btn-append,.append", container).trigger('click', template ? j : {
|
||||
key: i,
|
||||
value: j
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
63
view/addon/front.html
Normal file
63
view/addon/front.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<title>用户中心</title>
|
||||
<link rel="stylesheet" type="text/css" href="__static__/common/css/main.css?time={:time()}">
|
||||
<link rel="stylesheet" type="text/css" href="__css__/style.css?time={:time()}">
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="__static__/common/js/html5shiv.js"></script>
|
||||
<script src="__static__/common/js/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body class="hold-transition skin-blue sidebar-mini layout-top-nav">
|
||||
<div class="wrapper">
|
||||
<header class="main-header">
|
||||
<nav class="navbar navbar-static-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
</nav>
|
||||
</header>
|
||||
<!-- Full Width Column -->
|
||||
<div class="content-wrapper">
|
||||
<div class="container">
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
{block name="body"}
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"></h3>
|
||||
</div>
|
||||
<div class="box-body"></div>
|
||||
</div>
|
||||
{/block}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
<footer class="main-footer">
|
||||
<div class="pull-right hidden-xs">
|
||||
<b>Version</b> {$version}
|
||||
</div>
|
||||
<strong>Copyright © 2013-2020 <a href="https://www.tensent.cn">SentCMS</a>.</strong> All rights
|
||||
reserved.
|
||||
</footer>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var require = {
|
||||
config: {"site": {$config|json_encode|raw}, 'version':"{$version}", 'module': 'user', 'jsname': "{$require['jsname']|default=''}", 'actionname': "{$require['actionname']|default=''}", }
|
||||
}
|
||||
</script>
|
||||
<script src="__plugins__/require/require.js" data-main="/template/default/static/js/main.js"></script>
|
||||
{block name="script"}{/block}
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user