mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-21 19:22:45 +08:00
初步完成开放登录,待线上测试
This commit is contained in:
parent
753f2203fa
commit
eac442c0a0
@ -298,4 +298,33 @@ class SettingController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/oauth", name="admin.setting.oauth")
|
||||
*/
|
||||
public function oauthAction()
|
||||
{
|
||||
$settingService = new SettingService();
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
|
||||
$section = $this->request->getPost('section', 'string');
|
||||
|
||||
$data = $this->request->getPost();
|
||||
|
||||
$settingService->updateSettings($section, $data);
|
||||
|
||||
return $this->jsonSuccess(['msg' => '更新配置成功']);
|
||||
|
||||
} else {
|
||||
|
||||
$qqAuth = $settingService->getQQAuthSettings();
|
||||
$weixinAuth = $settingService->getWeixinAuthSettings();
|
||||
$weiboAuth = $settingService->getWeiboAuthSettings();
|
||||
|
||||
$this->view->setVar('qq_auth', $qqAuth);
|
||||
$this->view->setVar('weixin_auth', $weixinAuth);
|
||||
$this->view->setVar('weibo_auth', $weiboAuth);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -744,6 +744,12 @@ class AuthNode extends Service
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.setting.im',
|
||||
],
|
||||
[
|
||||
'id' => '5-1-12',
|
||||
'title' => '开放登录',
|
||||
'type' => 'menu',
|
||||
'route' => 'admin.setting.oauth',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -9,6 +9,33 @@ use App\Repos\Vip as VipRepo;
|
||||
class Setting extends Service
|
||||
{
|
||||
|
||||
public function getQQAuthSettings()
|
||||
{
|
||||
$oauth = $this->getSettings('oauth.qq');
|
||||
|
||||
$oauth['redirect_uri'] = $oauth['redirect_uri'] ?: kg_full_url(['for' => 'home.oauth.qq_callback']);
|
||||
|
||||
return $oauth;
|
||||
}
|
||||
|
||||
public function getWeixinAuthSettings()
|
||||
{
|
||||
$oauth = $this->getSettings('oauth.weixin');
|
||||
|
||||
$oauth['redirect_uri'] = $oauth['redirect_uri'] ?: kg_full_url(['for' => 'home.oauth.weixin_callback']);
|
||||
|
||||
return $oauth;
|
||||
}
|
||||
|
||||
public function getWeiboAuthSettings()
|
||||
{
|
||||
$oauth = $this->getSettings('oauth.weibo');
|
||||
|
||||
$oauth['redirect_uri'] = $oauth['redirect_uri'] ?: kg_full_url(['for' => 'home.oauth.weibo_callback']);
|
||||
|
||||
return $oauth;
|
||||
}
|
||||
|
||||
public function getAlipaySettings()
|
||||
{
|
||||
$alipay = $this->getSettings('pay.alipay');
|
||||
|
24
app/Http/Admin/Views/setting/oauth.volt
Normal file
24
app/Http/Admin/Views/setting/oauth.volt
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title kg-tab-title">
|
||||
<li class="layui-this">QQ登录</li>
|
||||
<li>微信登录</li>
|
||||
<li>新浪微博</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
{{ partial('setting/oauth_qq') }}
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
{{ partial('setting/oauth_weixin') }}
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
{{ partial('setting/oauth_weibo') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
35
app/Http/Admin/Views/setting/oauth_qq.volt
Normal file
35
app/Http/Admin/Views/setting/oauth_qq.volt
Normal file
@ -0,0 +1,35 @@
|
||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.oauth'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">开启登录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="enabled" value="1" title="是" {% if qq_auth.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="enabled" value="0" title="否" {% if qq_auth.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="client_id" value="{{ qq_auth.client_id }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App Secret</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="client_secret" value="{{ qq_auth.client_secret }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Redirect Url</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="redirect_uri" value="{{ qq_auth.redirect_uri }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
<input type="hidden" name="section" value="oauth.qq">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
35
app/Http/Admin/Views/setting/oauth_weibo.volt
Normal file
35
app/Http/Admin/Views/setting/oauth_weibo.volt
Normal file
@ -0,0 +1,35 @@
|
||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.oauth'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">开启登录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="enabled" value="1" title="是" {% if weibo_auth.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="enabled" value="0" title="否" {% if weibo_auth.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App Key</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="client_id" value="{{ weibo_auth.client_id }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App Secret</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="client_secret" value="{{ weibo_auth.client_secret }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Redirect Uri</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="redirect_uri" value="{{ weibo_auth.redirect_uri }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
<input type="hidden" name="section" value="oauth.weibo">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
35
app/Http/Admin/Views/setting/oauth_weixin.volt
Normal file
35
app/Http/Admin/Views/setting/oauth_weixin.volt
Normal file
@ -0,0 +1,35 @@
|
||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.oauth'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">开启登录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="enabled" value="1" title="是" {% if weixin_auth.enabled == "1" %}checked="checked"{% endif %}>
|
||||
<input type="radio" name="enabled" value="0" title="否" {% if weixin_auth.enabled == "0" %}checked="checked"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="client_id" value="{{ weixin_auth.client_id }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">App Secret</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="client_secret" value="{{ weixin_auth.client_secret }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Redirect Url</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="redirect_uri" value="{{ weixin_auth.redirect_uri }}" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
<input type="hidden" name="section" value="oauth.weixin">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
149
app/Http/Home/Controllers/ConnectController.php
Normal file
149
app/Http/Home/Controllers/ConnectController.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Home\Controllers;
|
||||
|
||||
use App\Http\Home\Services\Connect as ConnectService;
|
||||
use App\Models\Connect as ConnectModel;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/oauth")
|
||||
*/
|
||||
class ConnectController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @Get("/qq", name="home.oauth.qq")
|
||||
*/
|
||||
public function qqAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_QQ);
|
||||
|
||||
return $this->response->redirect($url, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/weixin", name="home.oauth.weixin")
|
||||
*/
|
||||
public function weixinAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_WEIXIN);
|
||||
|
||||
return $this->response->redirect($url, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/weibo", name="home.oauth.weibo")
|
||||
*/
|
||||
public function weiboAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_WEIBO);
|
||||
|
||||
return $this->response->redirect($url, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/qq/callback", name="home.oauth.qq_callback")
|
||||
*/
|
||||
public function qqCallbackAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
if ($this->authUser->id > 0) {
|
||||
|
||||
$service->bindUser(ConnectModel::PROVIDER_QQ);
|
||||
|
||||
return $this->response->redirect(['for' => 'home.uc.account']);
|
||||
}
|
||||
|
||||
$captcha = $service->getSettings('captcha');
|
||||
|
||||
$this->view->pick('connect/bind');
|
||||
$this->view->setVar('captcha', $captcha);
|
||||
$this->view->setVar('provider', ConnectModel::PROVIDER_QQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/weixin/callback", name="home.oauth.weixin_callback")
|
||||
*/
|
||||
public function weixinCallbackAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
if ($this->authUser->id > 0) {
|
||||
|
||||
$service->bindUser(ConnectModel::PROVIDER_WEIXIN);
|
||||
|
||||
return $this->response->redirect(['for' => 'home.uc.account']);
|
||||
}
|
||||
|
||||
$captcha = $service->getSettings('captcha');
|
||||
|
||||
$this->view->pick('connect/bind');
|
||||
$this->view->setVar('captcha', $captcha);
|
||||
$this->view->setVar('provider', ConnectModel::PROVIDER_QQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/weibo/callback", name="home.oauth.weibo_callback")
|
||||
*/
|
||||
public function weiboCallbackAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
if ($this->authUser->id > 0) {
|
||||
|
||||
$service->bindUser(ConnectModel::PROVIDER_WEIBO);
|
||||
|
||||
return $this->response->redirect(['for' => 'home.uc.account']);
|
||||
}
|
||||
|
||||
$captcha = $service->getSettings('captcha');
|
||||
|
||||
$this->view->pick('connect/bind');
|
||||
$this->view->setVar('captcha', $captcha);
|
||||
$this->view->setVar('provider', ConnectModel::PROVIDER_QQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/weibo/refuse", name="home.oauth.weibo_refuse")
|
||||
*/
|
||||
public function weiboRefuseAction()
|
||||
{
|
||||
return $this->response->redirect(['for' => 'home.account.login']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/bind/login", name="home.oauth.bind_login")
|
||||
*/
|
||||
public function bindLoginAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
$service->bindLogin();
|
||||
|
||||
$location = $this->url->get(['for' => 'home.uc.index']);
|
||||
|
||||
return $this->jsonSuccess(['location' => $location]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/bind/register", name="home.oauth.bind_register")
|
||||
*/
|
||||
public function bindRegisterAction()
|
||||
{
|
||||
$service = new ConnectService();
|
||||
|
||||
$service->bindRegister();
|
||||
|
||||
$location = $this->url->get(['for' => 'home.uc.index']);
|
||||
|
||||
return $this->jsonSuccess(['location' => $location]);
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
namespace App\Http\Home\Controllers;
|
||||
|
||||
use App\Services\Logic\User\Console\AccountInfo as AccountInfoService;
|
||||
use App\Services\Logic\User\Console\ConnectDelete as ConnectDeleteService;
|
||||
use App\Services\Logic\User\Console\ConnectList as ConnectListService;
|
||||
use App\Services\Logic\User\Console\ConsultList as ConsultListService;
|
||||
use App\Services\Logic\User\Console\CourseList as CourseListService;
|
||||
use App\Services\Logic\User\Console\FavoriteList as FavoriteListService;
|
||||
@ -59,13 +61,17 @@ class UserConsoleController extends Controller
|
||||
*/
|
||||
public function accountAction()
|
||||
{
|
||||
$type = $this->request->getQuery('type', 'string', 'info');
|
||||
|
||||
$service = new AccountInfoService();
|
||||
|
||||
$captcha = $service->getSettings('captcha');
|
||||
|
||||
$account = $service->handle();
|
||||
|
||||
$type = $this->request->getQuery('type', 'string', 'info');
|
||||
$service = new ConnectListService();
|
||||
|
||||
$connects = $service->handle();
|
||||
|
||||
if ($type == 'info') {
|
||||
$this->view->pick('user/console/account_info');
|
||||
@ -79,6 +85,7 @@ class UserConsoleController extends Controller
|
||||
|
||||
$this->view->setVar('captcha', $captcha);
|
||||
$this->view->setVar('account', $account);
|
||||
$this->view->setVar('connects', $connects);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,4 +214,23 @@ class UserConsoleController extends Controller
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/connect/{id:[0-9]+}/delete", name="home.uc.unconnect")
|
||||
*/
|
||||
public function deleteConnectAction($id)
|
||||
{
|
||||
$service = new ConnectDeleteService();
|
||||
|
||||
$service->handle($id);
|
||||
|
||||
$location = $this->url->get(['for' => 'home.uc.account']);
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '解除登录绑定成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
}
|
||||
|
167
app/Http/Home/Services/Connect.php
Normal file
167
app/Http/Home/Services/Connect.php
Normal file
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Home\Services;
|
||||
|
||||
use App\Library\OAuth\QQ as QQAuth;
|
||||
use App\Library\OAuth\WeiBo as WeiBoAuth;
|
||||
use App\Library\OAuth\WeiXin as WeiXinAuth;
|
||||
use App\Models\Connect as ConnectModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Connect as ConnectRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use App\Services\Logic\Account\Register as RegisterService;
|
||||
use App\Validators\Account as AccountValidator;
|
||||
|
||||
class Connect extends Service
|
||||
{
|
||||
|
||||
public function bindLogin()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$validator = new AccountValidator();
|
||||
|
||||
$user = $validator->checkUserLogin($post['account'], $post['password']);
|
||||
|
||||
$openUser = $this->getOpenUserInfo($post['code'], $post['stats'], $post['provider']);
|
||||
|
||||
$this->handleBindRelation($user, $openUser, $post['provider']);
|
||||
|
||||
$this->auth->saveAuthInfo($user);
|
||||
}
|
||||
|
||||
public function bindRegister()
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$openUser = $this->getOpenUserInfo($post['code'], $post['state'], $post['provider']);
|
||||
|
||||
$registerService = new RegisterService();
|
||||
|
||||
$account = $registerService->handle();
|
||||
|
||||
$userRepo = new UserRepo();
|
||||
|
||||
$user = $userRepo->findById($account->id);
|
||||
|
||||
$this->handleBindRelation($user, $openUser, $post['provider']);
|
||||
|
||||
$this->auth->saveAuthInfo($user);
|
||||
}
|
||||
|
||||
public function bindUser($provider)
|
||||
{
|
||||
$code = $this->request->getQuery('code', 'trim');
|
||||
$state = $this->request->getQuery('state', 'trim');
|
||||
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$openUser = $this->getOpenUserInfo($code, $state, $provider);
|
||||
|
||||
$this->handleBindRelation($user, $openUser, $provider);
|
||||
}
|
||||
|
||||
public function getAuthorizeUrl($provider)
|
||||
{
|
||||
$auth = $this->getAuth($provider);
|
||||
|
||||
return $auth->getAuthorizeUrl();
|
||||
}
|
||||
|
||||
public function getAuth($provider)
|
||||
{
|
||||
$auth = null;
|
||||
|
||||
switch ($provider) {
|
||||
case ConnectModel::PROVIDER_QQ:
|
||||
$auth = $this->getQQAuth();
|
||||
break;
|
||||
case ConnectModel::PROVIDER_WEIXIN:
|
||||
$auth = $this->getWeiXinAuth();
|
||||
break;
|
||||
case ConnectModel::PROVIDER_WEIBO:
|
||||
$auth = $this->getWeiBoAuth();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$auth) {
|
||||
throw new \Exception('Invalid OAuth Provider');
|
||||
}
|
||||
|
||||
return $auth;
|
||||
}
|
||||
|
||||
protected function getQQAuth()
|
||||
{
|
||||
$settings = $this->getSettings('oauth.qq');
|
||||
|
||||
return new QQAuth(
|
||||
$settings['client_id'],
|
||||
$settings['client_secret'],
|
||||
$settings['redirect_uri']
|
||||
);
|
||||
}
|
||||
|
||||
protected function getWeiXinAuth()
|
||||
{
|
||||
$settings = $this->getSettings('oauth.weixin');
|
||||
|
||||
return new WeiXinAuth(
|
||||
$settings['client_id'],
|
||||
$settings['client_secret'],
|
||||
$settings['redirect_uri']
|
||||
);
|
||||
}
|
||||
|
||||
protected function getWeiBoAuth()
|
||||
{
|
||||
$settings = $this->getSettings('oauth.weibo');
|
||||
|
||||
return new WeiBoAuth(
|
||||
$settings['client_id'],
|
||||
$settings['client_secret'],
|
||||
$settings['redirect_uri']
|
||||
);
|
||||
}
|
||||
|
||||
protected function getOpenUserInfo($code, $state, $provider)
|
||||
{
|
||||
$auth = $this->getAuth($provider);
|
||||
|
||||
$auth->checkState($state);
|
||||
|
||||
$token = $auth->getAccessToken($code);
|
||||
|
||||
$openId = $auth->getOpenId($token);
|
||||
|
||||
return $auth->getUserInfo($token, $openId);
|
||||
}
|
||||
|
||||
protected function handleBindRelation(UserModel $user, array $openUser, $provider)
|
||||
{
|
||||
$connectRepo = new ConnectRepo();
|
||||
|
||||
$connect = $connectRepo->findByOpenId($openUser['id'], $provider);
|
||||
|
||||
if ($connect) {
|
||||
|
||||
if ($connect->deleted == 1) {
|
||||
$connect->deleted = 0;
|
||||
$connect->update();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$connect = new ConnectModel();
|
||||
|
||||
$connect->user_id = $user->id;
|
||||
$connect->open_id = $openUser['id'];
|
||||
$connect->open_name = $openUser['name'];
|
||||
$connect->open_avatar = $openUser['avatar'];
|
||||
$connect->provider = $provider;
|
||||
|
||||
$connect->create();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,11 @@
|
||||
<span class="separator">·</span>
|
||||
<a class="forget-link" href="{{ url({'for':'home.account.forget_pwd'}) }}">忘记密码</a>
|
||||
</div>
|
||||
<div class="oauth">
|
||||
<a class="layui-icon layui-icon-login-qq login-qq" href="{{ url({'for':'home.oauth.qq'}) }}"></a>
|
||||
<a class="layui-icon layui-icon-login-wechat login-wechat" href="{{ url({'for':'home.oauth.weixin'}) }}"></a>
|
||||
<a class="layui-icon layui-icon-login-weibo login-weibo" href="{{ url({'for':'home.oauth.weibo'}) }}"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
34
app/Http/Home/Views/connect/bind.volt
Normal file
34
app/Http/Home/Views/connect/bind.volt
Normal file
@ -0,0 +1,34 @@
|
||||
{% extends 'templates/main.volt' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="layui-breadcrumb breadcrumb">
|
||||
<a href="/">首页</a>
|
||||
<a><cite>登录绑定</cite></a>
|
||||
</div>
|
||||
|
||||
<div class="login-wrap wrap">
|
||||
<div class="layui-tab layui-tab-brief login-tab">
|
||||
<ul class="layui-tab-title login-tab-title">
|
||||
<li class="layui-this">绑定已有帐号</li>
|
||||
<li>注册并绑定帐号</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
{{ partial('connect/bind_login') }}
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
{{ partial('connect/bind_register') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://ssl.captcha.qq.com/TCaptcha.js',false) }}
|
||||
{{ js_include('home/js/captcha.verify.js') }}
|
||||
|
||||
{% endblock %}
|
20
app/Http/Home/Views/connect/bind_login.volt
Normal file
20
app/Http/Home/Views/connect/bind_login.volt
Normal file
@ -0,0 +1,20 @@
|
||||
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.oauth.bind_login'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button id="submit-btn" class="layui-btn layui-btn-fluid" lay-submit="true" lay-filter="go">登录并绑定已有帐号</button>
|
||||
<input type="hidden" name="provider" value="{{ provider }}">
|
||||
<input type="hidden" name="code" value="{{ request.get.code }}">
|
||||
<input type="hidden" name="state" value="{{ request.get.state }}">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
31
app/Http/Home/Views/connect/bind_register.volt
Normal file
31
app/Http/Home/Views/connect/bind_register.volt
Normal file
@ -0,0 +1,31 @@
|
||||
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.oauth.bind_register'}) }}">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码(字母数字特殊字符6-16位)" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-inline verify-input-inline">
|
||||
<input class="layui-input" type="text" name="verify_code" placeholder="验证码" lay-verify="required">
|
||||
</div>
|
||||
<div class="layui-input-inline verify-btn-inline">
|
||||
<button id="cv-verify-emit" class="layui-btn layui-btn-primary layui-btn-disabled" type="button" disabled="disabled">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button id="cv-submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" disabled="disabled" lay-submit="true" lay-filter="go">注册并绑定帐号</button>
|
||||
<input type="hidden" name="provider" value="{{ provider }}">
|
||||
<input type="hidden" name="code" value="{{ request.get.code }}">
|
||||
<input type="hidden" name="state" value="{{ request.get.state }}">
|
||||
<input id="cv-app-id" type="hidden" value="{{ captcha.app_id }}">
|
||||
<input id="cv-ticket" type="hidden" name="ticket">
|
||||
<input id="cv-rand" type="hidden" name="rand">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -2,6 +2,23 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{%- macro connect_provider(item) %}
|
||||
{% if item.provider == 1 %}
|
||||
<i class="layui-icon layui-icon-login-qq login-qq"></i>
|
||||
{% elseif item.provider == 2 %}
|
||||
<i class="layui-icon layui-icon-login-wechat login-wechat"></i>
|
||||
{% elseif item.provider == 3 %}
|
||||
<i class="layui-icon layui-icon-login-weibo login-weibo"></i>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro connect_user(item) %}
|
||||
{% if item.open_avatar %}
|
||||
<span class="open-avatar"><img src="{{ item.open_avatar }}"></span>
|
||||
{% endif %}
|
||||
<span class="open-name">{{ item.open_name }}</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% set edit_pwd_url = url({'for':'home.uc.account'},{'type':'password'}) %}
|
||||
{% set edit_phone_url = url({'for':'home.uc.account'},{'type':'phone'}) %}
|
||||
{% set edit_email_url = url({'for':'home.uc.account'},{'type':'email'}) %}
|
||||
@ -43,6 +60,37 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-nav">
|
||||
<span class="title">开放登录</span>
|
||||
</div>
|
||||
<div class="connect-tips">已经绑定的第三方帐号</div>
|
||||
<div class="connect-list">
|
||||
<table class="layui-table">
|
||||
<tr>
|
||||
<td>序号</td>
|
||||
<td>提供方</td>
|
||||
<td>用户信息</td>
|
||||
<td>创建日期</td>
|
||||
<td width="15%">操作</td>
|
||||
</tr>
|
||||
{% for connect in connects %}
|
||||
{% set url = url({'for':'home.uc.unconnect','id':connect.id}) %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ connect_provider(connect) }}</td>
|
||||
<td>{{ connect_user(connect) }}</td>
|
||||
<td>{{ date('Y-m-d H:i',connect.create_time) }}</td>
|
||||
<td><a class="layui-btn layui-btn-danger layui-btn-sm kg-delete" href="javascript:" data-url="{{ url }}" data-tips="确定要解除绑定吗?">解除绑定</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
<div class="connect-tips">支持绑定的第三方帐号</div>
|
||||
<div class="oauth-list">
|
||||
<a class="layui-icon layui-icon-login-qq login-qq" href="{{ url({'for':'home.oauth.qq'}) }}"></a>
|
||||
<a class="layui-icon layui-icon-login-wechat login-wechat" href="{{ url({'for':'home.oauth.weixin'}) }}"></a>
|
||||
<a class="layui-icon layui-icon-login-weibo login-weibo" href="{{ url({'for':'home.oauth.weibo'}) }}"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,20 +3,22 @@
|
||||
namespace App\Library;
|
||||
|
||||
use GuzzleHttp\Client as HttpClient;
|
||||
use Phalcon\Crypt;
|
||||
use Phalcon\Di;
|
||||
|
||||
abstract class OAuth
|
||||
{
|
||||
|
||||
protected $appId;
|
||||
protected $appSecret;
|
||||
protected $clientId;
|
||||
protected $clientSecret;
|
||||
protected $redirectUri;
|
||||
protected $accessToken;
|
||||
protected $openId;
|
||||
|
||||
public function __construct($appId, $appSecret, $redirectUri)
|
||||
public function __construct($clientId, $clientSecret, $redirectUri)
|
||||
{
|
||||
$this->appId = $appId;
|
||||
$this->appSecret = $appSecret;
|
||||
$this->clientId = $clientId;
|
||||
$this->clientSecret = $clientSecret;
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
||||
@ -42,6 +44,32 @@ abstract class OAuth
|
||||
return $response->getBody();
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
/**
|
||||
* @var $crypt Crypt
|
||||
*/
|
||||
$crypt = Di::getDefault()->get('crypt');
|
||||
|
||||
return $crypt->encryptBase64(rand(1000, 9999));
|
||||
}
|
||||
|
||||
public function checkState($state)
|
||||
{
|
||||
/**
|
||||
* @var $crypt Crypt
|
||||
*/
|
||||
$crypt = Di::getDefault()->get('crypt');
|
||||
|
||||
$value = $crypt->decryptBase64($state);
|
||||
|
||||
if ($value < 1000 || $value > 9999) {
|
||||
throw new \Exception('Invalid OAuth State Value');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract public function getAuthorizeUrl();
|
||||
|
||||
abstract public function getAccessToken($code);
|
||||
|
@ -15,10 +15,11 @@ class QQ extends OAuth
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$params = [
|
||||
'client_id' => $this->appId,
|
||||
'client_id' => $this->clientId,
|
||||
'redirect_uri' => $this->redirectUri,
|
||||
'state' => $this->getState(),
|
||||
'response_type' => 'code',
|
||||
'scope' => '',
|
||||
'scope' => 'get_user_info',
|
||||
];
|
||||
|
||||
return self::AUTHORIZE_URL . '?' . http_build_query($params);
|
||||
@ -28,8 +29,8 @@ class QQ extends OAuth
|
||||
{
|
||||
$params = [
|
||||
'code' => $code,
|
||||
'client_id' => $this->appId,
|
||||
'client_secret' => $this->appSecret,
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
'redirect_uri' => $this->redirectUri,
|
||||
'grant_type' => 'authorization_code',
|
||||
'state' => 'ok',
|
||||
@ -56,14 +57,14 @@ class QQ extends OAuth
|
||||
public function getUserInfo($accessToken, $openId)
|
||||
{
|
||||
$params = [
|
||||
'oauth_consumer_key' => $this->clientId,
|
||||
'access_token' => $accessToken,
|
||||
'openid' => $openId,
|
||||
'oauth_consumer_key' => $this->appId,
|
||||
];
|
||||
|
||||
$response = $this->httpGet(self::USER_INFO_URL, $params);
|
||||
|
||||
$this->parseUserInfo($response);
|
||||
|
||||
return $this->parseUserInfo($response);
|
||||
}
|
||||
|
||||
protected function parseAccessToken($response)
|
||||
@ -81,11 +82,11 @@ class QQ extends OAuth
|
||||
|
||||
protected function parseOpenId($response)
|
||||
{
|
||||
$result = $match = [];
|
||||
$result = $matches = [];
|
||||
|
||||
if (!empty($response)) {
|
||||
preg_match('/callback\(\s+(.*?)\s+\)/i', $response, $match);
|
||||
$result = json_decode($match[1], true);
|
||||
preg_match('/callback\(\s+(.*?)\s+\)/i', $response, $matches);
|
||||
$result = json_decode($matches[1], true);
|
||||
}
|
||||
|
||||
if (!isset($result['openid'])) {
|
||||
@ -98,16 +99,16 @@ class QQ extends OAuth
|
||||
protected function parseUserInfo($response)
|
||||
{
|
||||
$data = json_decode($response, true);
|
||||
|
||||
|
||||
if ($data['ret'] != 0) {
|
||||
throw new \Exception("Fetch User Info Failed:{$data['msg']}");
|
||||
}
|
||||
|
||||
$userInfo['type'] = 'QQ';
|
||||
|
||||
$userInfo['id'] = $this->openId;
|
||||
$userInfo['name'] = $data['nickname'];
|
||||
$userInfo['nick'] = $data['nickname'];
|
||||
$userInfo['head'] = $data['figureurl_2'];
|
||||
|
||||
$userInfo['avatar'] = $data['figureurl_2'];
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,9 @@ class WeiBo extends OAuth
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$params = [
|
||||
'client_id' => $this->appId,
|
||||
'client_id' => $this->clientId,
|
||||
'redirect_uri' => $this->redirectUri,
|
||||
'state' => $this->getState(),
|
||||
'response_type' => 'code',
|
||||
];
|
||||
|
||||
@ -26,8 +27,8 @@ class WeiBo extends OAuth
|
||||
{
|
||||
$params = [
|
||||
'code' => $code,
|
||||
'client_id' => $this->appId,
|
||||
'client_secret' => $this->appSecret,
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
'redirect_uri' => $this->redirectUri,
|
||||
'grant_type' => 'authorization_code',
|
||||
];
|
||||
@ -72,16 +73,16 @@ class WeiBo extends OAuth
|
||||
private function parseUserInfo($response)
|
||||
{
|
||||
$data = json_decode($response, true);
|
||||
|
||||
|
||||
if ($data['error_code'] != 0) {
|
||||
throw new \Exception("Fetch User Info Failed:{$data['error']}");
|
||||
}
|
||||
|
||||
$userInfo['type'] = 'WEIBO';
|
||||
|
||||
$userInfo['id'] = $this->openId;
|
||||
$userInfo['name'] = $data['name'];
|
||||
$userInfo['nick'] = $data['screen_name'];
|
||||
$userInfo['head'] = $data['avatar_large'];
|
||||
|
||||
$userInfo['avatar'] = $data['avatar_large'];
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,11 @@ class WeiXin extends OAuth
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$params = [
|
||||
'appid' => $this->appId,
|
||||
'appid' => $this->clientId,
|
||||
'redirect_uri' => $this->redirectUri,
|
||||
'state' => $this->getState(),
|
||||
'response_type' => 'code',
|
||||
'scope' => 'snsapi_login',
|
||||
'state' => 'dev',
|
||||
];
|
||||
|
||||
return self::AUTHORIZE_URL . '?' . http_build_query($params);
|
||||
@ -28,8 +28,8 @@ class WeiXin extends OAuth
|
||||
{
|
||||
$params = [
|
||||
'code' => $code,
|
||||
'appid' => $this->appId,
|
||||
'secret' => $this->appSecret,
|
||||
'appid' => $this->clientId,
|
||||
'secret' => $this->clientSecret,
|
||||
'grant_type' => 'authorization_code',
|
||||
];
|
||||
|
||||
@ -73,16 +73,16 @@ class WeiXin extends OAuth
|
||||
private function parseUserInfo($response)
|
||||
{
|
||||
$data = json_decode($response, true);
|
||||
|
||||
|
||||
if (isset($data['errcode']) && $data['errcode'] != 0) {
|
||||
throw new \Exception("Fetch User Info Failed:{$data['errmsg']}");
|
||||
}
|
||||
|
||||
$userInfo['type'] = 'WEIXIN';
|
||||
|
||||
$userInfo['id'] = $this->openId;
|
||||
$userInfo['name'] = $data['name'];
|
||||
$userInfo['nick'] = $data['screen_name'];
|
||||
$userInfo['head'] = $data['avatar_large'];
|
||||
|
||||
$userInfo['avatar'] = $data['avatar_large'];
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
|
104
app/Models/Connect.php
Normal file
104
app/Models/Connect.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Phalcon\Mvc\Model\Behavior\SoftDelete;
|
||||
|
||||
class Connect extends Model
|
||||
{
|
||||
|
||||
const PROVIDER_QQ = 1; // QQ
|
||||
const PROVIDER_WEIXIN = 2; // 微信
|
||||
const PROVIDER_WEIBO = 3; // 微博
|
||||
|
||||
/**
|
||||
* 主键编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $user_id;
|
||||
|
||||
/**
|
||||
* 开放ID
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $open_id;
|
||||
|
||||
/**
|
||||
* 开放名称
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $open_name;
|
||||
|
||||
/**
|
||||
* 开放头像
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $open_avatar;
|
||||
|
||||
/**
|
||||
* 提供商
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $provider;
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
return 'kg_connect';
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
$this->addBehavior(
|
||||
new SoftDelete([
|
||||
'field' => 'deleted',
|
||||
'value' => 1,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
public function beforeCreate()
|
||||
{
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
public function beforeUpdate()
|
||||
{
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
}
|
62
app/Repos/Connect.php
Normal file
62
app/Repos/Connect.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use App\Models\Connect as ConnectModel;
|
||||
use Phalcon\Mvc\Model;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class Connect extends Repository
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $where
|
||||
* @return ResultsetInterface|Resultset|ConnectModel[]
|
||||
*/
|
||||
public function findAll($where = [])
|
||||
{
|
||||
$query = ConnectModel::query();
|
||||
|
||||
$query->where('1 = 1');
|
||||
|
||||
if (isset($where['user_id'])) {
|
||||
$query->andWhere('user_id = :user_id:', ['user_id' => $where['user_id']]);
|
||||
}
|
||||
|
||||
if (isset($where['provider'])) {
|
||||
$query->andWhere('provider = :provider:', ['provider' => $where['provider']]);
|
||||
}
|
||||
|
||||
if (isset($where['deleted'])) {
|
||||
$query->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
|
||||
}
|
||||
|
||||
$query->orderBy('id DESC');
|
||||
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return ConnectModel|Model|bool
|
||||
*/
|
||||
public function findById($id)
|
||||
{
|
||||
return ConnectModel::findFirst($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $openId
|
||||
* @param int $provider
|
||||
* @return ConnectModel|Model|bool
|
||||
*/
|
||||
public function findByOpenId($openId, $provider)
|
||||
{
|
||||
return ConnectModel::findFirst([
|
||||
'conditions' => 'open_id = ?1 and provider = ?2',
|
||||
'bind' => [1 => $openId, 2 => $provider],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
26
app/Services/Logic/User/Console/ConnectDelete.php
Normal file
26
app/Services/Logic/User/Console/ConnectDelete.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\User\Console;
|
||||
|
||||
use App\Services\Logic\Service;
|
||||
use App\Validators\Connect as ConnectValidator;
|
||||
|
||||
class ConnectDelete extends Service
|
||||
{
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$validator = new ConnectValidator();
|
||||
|
||||
$connect = $validator->checkConnect($id);
|
||||
|
||||
$validator->checkOwner($user->id, $connect->user_id);
|
||||
|
||||
$connect->deleted = 1;
|
||||
|
||||
$connect->update();
|
||||
}
|
||||
|
||||
}
|
45
app/Services/Logic/User/Console/ConnectList.php
Normal file
45
app/Services/Logic/User/Console/ConnectList.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Logic\User\Console;
|
||||
|
||||
use App\Repos\Connect as ConnectRepo;
|
||||
use App\Services\Logic\Service;
|
||||
|
||||
class ConnectList extends Service
|
||||
{
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$user = $this->getLoginUser();
|
||||
|
||||
$params = [
|
||||
'user_id' => $user->id,
|
||||
'deleted' => 0,
|
||||
];
|
||||
|
||||
$connectRepo = new ConnectRepo();
|
||||
|
||||
$connects = $connectRepo->findAll($params);
|
||||
|
||||
if ($connects->count() == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($connects as $connect) {
|
||||
$items[] = [
|
||||
'id' => $connect->id,
|
||||
'open_id' => $connect->open_id,
|
||||
'open_name' => $connect->open_name,
|
||||
'open_avatar' => $connect->open_avatar,
|
||||
'provider' => $connect->provider,
|
||||
'create_time' => $connect->create_time,
|
||||
'update_time' => $connect->update_time,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
}
|
41
app/Validators/Connect.php
Normal file
41
app/Validators/Connect.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Validators;
|
||||
|
||||
use App\Exceptions\BadRequest as BadRequestException;
|
||||
use App\Repos\Connect as ConnectRepo;
|
||||
|
||||
class Connect extends Validator
|
||||
{
|
||||
|
||||
public function checkConnect($id)
|
||||
{
|
||||
return $this->checkConnectById($id);
|
||||
}
|
||||
|
||||
public function checkConnectById($id)
|
||||
{
|
||||
$connectRepo = new ConnectRepo();
|
||||
|
||||
$connect = $connectRepo->findById($id);
|
||||
|
||||
if (!$connect) {
|
||||
throw new BadRequestException('connect.not_found');
|
||||
}
|
||||
|
||||
return $connect;
|
||||
}
|
||||
|
||||
public function checkConnectByOpenId($openId, $provider)
|
||||
{
|
||||
$connectRepo = new ConnectRepo();
|
||||
|
||||
$connect = $connectRepo->findByOpenId($openId, $provider);
|
||||
|
||||
if (!$connect) {
|
||||
throw new BadRequestException('connect.not_found');
|
||||
}
|
||||
|
||||
return $connect;
|
||||
}
|
||||
}
|
92
db/migrations/20201205091213_create_connect_table.php
Normal file
92
db/migrations/20201205091213_create_connect_table.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
class CreateConnectTable extends Phinx\Migration\AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$this->table('kg_connect', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'comment' => '',
|
||||
'row_format' => 'DYNAMIC',
|
||||
])
|
||||
->addColumn('id', 'integer', [
|
||||
'null' => false,
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'identity' => 'enable',
|
||||
'comment' => '主键编号',
|
||||
])
|
||||
->addColumn('user_id', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '用户编号',
|
||||
'after' => 'id',
|
||||
])
|
||||
->addColumn('open_id', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 50,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '开放ID',
|
||||
'after' => 'user_id',
|
||||
])
|
||||
->addColumn('open_name', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 30,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '开放名称',
|
||||
'after' => 'open_id',
|
||||
])
|
||||
->addColumn('open_avatar', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 150,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '开放头像',
|
||||
'after' => 'open_name',
|
||||
])
|
||||
->addColumn('provider', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '提供方',
|
||||
'after' => 'open_avatar',
|
||||
])
|
||||
->addColumn('deleted', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '删除标识',
|
||||
'after' => 'provider',
|
||||
])
|
||||
->addColumn('create_time', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '创建时间',
|
||||
'after' => 'deleted',
|
||||
])
|
||||
->addColumn('update_time', 'integer', [
|
||||
'null' => false,
|
||||
'default' => '0',
|
||||
'limit' => MysqlAdapter::INT_REGULAR,
|
||||
'comment' => '更新时间',
|
||||
'after' => 'create_time',
|
||||
])
|
||||
->addIndex(['open_id', 'provider'], [
|
||||
'name' => 'openid_provider',
|
||||
'unique' => false,
|
||||
])
|
||||
->create();
|
||||
}
|
||||
}
|
85
db/migrations/20201205112717_insert_oauth_setting_data.php
Normal file
85
db/migrations/20201205112717_insert_oauth_setting_data.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class InsertOauthSettingData extends AbstractMigration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
$rows = [
|
||||
[
|
||||
'section' => 'oauth.qq',
|
||||
'item_key' => 'enabled',
|
||||
'item_value' => '0',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.qq',
|
||||
'item_key' => 'client_id',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.qq',
|
||||
'item_key' => 'client_secret',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.qq',
|
||||
'item_key' => 'redirect_uri',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weixin',
|
||||
'item_key' => 'enabled',
|
||||
'item_value' => '0',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weixin',
|
||||
'item_key' => 'client_id',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weixin',
|
||||
'item_key' => 'client_secret',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weixin',
|
||||
'item_key' => 'redirect_uri',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weibo',
|
||||
'item_key' => 'enabled',
|
||||
'item_value' => '0',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weibo',
|
||||
'item_key' => 'client_id',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weibo',
|
||||
'item_key' => 'client_secret',
|
||||
'item_value' => '',
|
||||
],
|
||||
[
|
||||
'section' => 'oauth.weibo',
|
||||
'item_key' => 'redirect_uri',
|
||||
'item_value' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$this->table('kg_setting')->insert($rows)->save();
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->execute("DELETE FROM kg_setting WHERE section = 'oauth.qq'");
|
||||
$this->execute("DELETE FROM kg_setting WHERE section = 'oauth.weixin'");
|
||||
$this->execute("DELETE FROM kg_setting WHERE section = 'oauth.weibo'");
|
||||
}
|
||||
|
||||
}
|
@ -1188,7 +1188,7 @@
|
||||
}
|
||||
|
||||
.login-wrap .link {
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
@ -1202,6 +1202,26 @@
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.login-wrap .oauth {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-wrap .oauth a {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.login-qq {
|
||||
color: dodgerblue;
|
||||
}
|
||||
|
||||
.login-wechat {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.login-weibo {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.user-profile {
|
||||
position: relative;
|
||||
}
|
||||
@ -1537,9 +1557,12 @@
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.security-item-list {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.security-item {
|
||||
padding: 15px;
|
||||
line-height: 50px;
|
||||
line-height: 80px;
|
||||
border-bottom: 1px dashed #ccc;
|
||||
}
|
||||
|
||||
@ -1563,6 +1586,29 @@
|
||||
float: right;
|
||||
}
|
||||
|
||||
.connect-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.open-avatar img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.connect-tips {
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.oauth-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.oauth-list a {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.order-filter {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user