接入钉钉,实现钉钉扫码登录

Signed-off-by: vilson <545522390@qq.com>
This commit is contained in:
vilson 2019-06-24 19:10:06 +08:00
parent 5448a88197
commit a628429934
10 changed files with 293 additions and 79 deletions

View File

@ -5,7 +5,7 @@ use service\NodeService;
use service\RandomService;
use think\Db;
use think\facade\Cache;
use think\facade\Request;
use think\facade\Log;
function isDebug()
@ -13,6 +13,54 @@ function isDebug()
return config('app.app_debug');
}
/**
* 日志记录
* @param string|array $content 内容
* @param string $type 日志类型
* @param string $path 日志地址
*/
function logRecord($content, $type = 'info', $path = 'default')
{
$path = 'log/' . $path;
Log::init(['path' => $path]);
if (is_array($content) || is_object($content)) {
$content = json_encode($content);
}
Log::write($content, $type);
Log::init();
}
function getCurrentMember()
{
return session('member');
}
function setCurrentMember($data)
{
return session('member', $data);
}
function getCurrentOrganizationCode()
{
return session('currentOrganizationCode');
}
function setCurrentOrganizationCode($data)
{
return session('currentOrganizationCode', $data);
}
function getCurrentOrganization()
{
return session('organization');
}
function setCurrentOrganization($data)
{
return session('organization', $data);
}
/**
* 打印输出数据到文件
* @param mixed $data 输出的数据
@ -180,8 +228,8 @@ function decode($string)
/**
* 获取锁
* @param String $key 锁标识
* @param Int $expire 锁过期时间
* @param String $key 锁标识
* @param Int $expire 锁过期时间
* @return Boolean
*/
function lock($key = '', $expire = 5)
@ -197,7 +245,7 @@ function lock($key = '', $expire = 5)
/**
* 释放锁
* @param String $key 锁标识
* @param String $key 锁标识
* @return Boolean
*/
function unlock($key = '')

View File

@ -2,6 +2,9 @@
namespace app\common\Model;
use service\JwtService;
use service\NodeService;
use service\RandomService;
use think\Db;
use think\File;
@ -10,13 +13,38 @@ class Member extends CommonModel
protected $append = [];
public function login($account)
public static function login($member)
{
if ($account == 'admin') {
return [];
// 更新登录信息
Db::name('Member')->where(['id' => $member['id']])->update([
'last_login_time' => Db::raw('now()'),
]);
$list = MemberAccount::where(['member_code' => $member['code']])->order('id asc')->select()->toArray();
$organizationList = [];
if ($list) {
foreach ($list as $item) {
$organization = Organization::where(['code' => $item['organization_code']])->find();
if ($organization) {
$organizationList[] = $organization;
}
}
}
$where[] = ['account', '=', $account];
return Db::name('member')->where($where)->find();
$member['account_id'] = $list[0]['id'];
$member['is_owner'] = $list[0]['is_owner'];
$member['authorize'] = $list[0]['authorize'];
$member['position'] = $list[0]['position'];
$member['department'] = $list[0]['department'];
setCurrentMember($member);
!empty($member['authorize']) && NodeService::applyProjectAuthNode();
$member = getCurrentMember();
$tokenList = JwtService::initToken($member);
$accessTokenExp = JwtService::decodeToken($tokenList['accessToken'])->exp;
$tokenList['accessTokenExp'] = $accessTokenExp;
$loginInfo = ['member' => $member, 'tokenList' => $tokenList, 'organizationList' => $organizationList];
session('loginInfo', $loginInfo);
logRecord($loginInfo, 'info', 'member/login');
return $loginInfo;
}
/**
@ -30,6 +58,10 @@ class Member extends CommonModel
{
//需要创建的信息。1、用户 2、用户所属组织 3、组织权限 4、所属组织账号
$memberData['create_time'] = nowTime();
(!isset($memberData['avatar']) || !$memberData['avatar']) && $memberData['avatar'] = 'https://static.vilson.xyz/cover.png';
!isset($memberData['status']) && $memberData['status'] = 1;
!isset($memberData['code']) && $memberData['code'] = createUniqueCode('member');
!isset($memberData['account']) && $memberData['account'] = RandomService::alnumLowercase();
$result = self::create($memberData);
@ -80,6 +112,25 @@ class Member extends CommonModel
return $result;
}
public static function dingtalkLogin($userInfo)
{
$unionid = $userInfo['unionid'];
$openid = $userInfo['openid'];
$member = self::where(['dingtalk_unionid' => $unionid])->find();
if (!$member) {
$memberData = [
'dingtalk_openid' => $openid,
'dingtalk_unionid' => $unionid,
'name' => $userInfo['nick'],
'avatar' => isset($userInfo['avatar']) ? $userInfo['avatar'] : '',
'mobile' => isset($userInfo['mobile']) ? $userInfo['mobile'] : '',
'email' => isset($userInfo['email']) ? $userInfo['email'] : '',
];
$member = self::createMember($memberData);
}
self::login($member);
return $member;
}
/**
* @param File $file

View File

@ -65,7 +65,7 @@ class Organization extends CommonModel
'create_time' => nowTime(),
'avatar' => $memberData['avatar'],
'name' => $memberData['name'],
'email' => $memberData['email'],
'email' => isset($memberData['email']) ? $memberData['email'] : '',
];
MemberAccount::create($memberAccountData);
return $organization;

View File

@ -0,0 +1,85 @@
<?php
/**
* Created by PhpStorm.
* User: Lenovo
* Date: 2019/1/2
* Time: 15:03
*/
namespace app\index\controller;
use app\common\Model\Client;
use app\common\Model\Member;
use controller\BasicApi;
use EasyDingTalk\Application;
use Symfony\Component\HttpFoundation\RedirectResponse;
use think\facade\Log;
use think\facade\Request;
use think\response\Redirect;
class Oauth extends BasicApi
{
public function index()
{
$app = new Application(config('dingtalk.'));
$userId = $app->user->getUseridByUnionid('3CnKFHEE7mX1hayPIHvpCwiEiE');
// echo json_encode($userId);die;
$userId = $userId['userid'];
$user = $app->user->get($userId, $lang = null);
echo json_encode($user);die;
}
public function dingTalkOauth()
{
$currentMember = getCurrentMember();
if (!$currentMember) {
$app = new Application(config('dingtalk.'));
$response = $app->oauth->use('app-01')->withQrConnect()->redirect();
$redirect = $response->getTargetUrl();
if ($redirect) {
if ($redirect == 'undefined') {
$redirect = '/';
}
$_SESSION['target_url'] = $redirect;
}
return redirect($redirect);
} else {
//已登录跳转
return redirect(Request::domain() . '/index.html');
}
}
/**
* 获取钉钉授权
* @return RedirectResponse|Redirect
*/
public function dingTalkOauthCallback()
{
$app = new Application(config('dingtalk.'));
$data = Request::param();
logRecord($data);
$user = $app->oauth->use('app-01')->user();
$response = $app->oauth->use('app-01')->redirect();
$redirect = $response->getTargetUrl();
logRecord($redirect);
logRecord($user);
//用户注册/绑定微信
$targetUrl = '/index.html#/member/login?logged=1';
if (!$user['errcode']) {
$result = $app->user->getUseridByUnionid($user['user_info']['unionid']);
if (!$result['errcode']) {
$user['user_info']['avatar'] = $result['avatar'];
$user['user_info']['mobile'] = $result['mobile'];
$user['user_info']['email'] = $result['email'];
}
Member::dingtalkLogin($user['user_info']);
}else{
$targetUrl = '/index.html#/member/login?logged=0&message=钉钉登录失败,请重试';
}
// 登录成功跳转
return redirect(Request::domain() . $targetUrl);
}
}

View File

@ -37,33 +37,3 @@ function _uploadFile(File $file, $path_name = '', $saveName = false)
function getCurrentMember()
{
return session('member');
}
function setCurrentMember($data)
{
return session('member', $data);
}
function getCurrentOrganizationCode()
{
return session('currentOrganizationCode');
}
function setCurrentOrganizationCode($data)
{
return session('currentOrganizationCode', $data);
}
function getCurrentOrganization()
{
return session('organization');
}
function setCurrentOrganization($data)
{
return session('organization', $data);
}

View File

@ -31,13 +31,13 @@ class Index extends BasicApi
/**
* @title 用户菜单
* @description 获取用户菜单列表
* @author PearProject
* @url /project/index
* @method GET
* @return void :名称
* @throws DataNotFoundException
* @throws ModelNotFoundException
* @throws DbException
* @author PearProject
* @url /project/index
* @method GET
*/
public function index()
{
@ -81,7 +81,6 @@ class Index extends BasicApi
}
/**
* 个人个信息
* @throws DataNotFoundException

View File

@ -42,15 +42,15 @@ class Login extends BasicApi
/**
* @title 用户登录
* @description 用户登录
* @author PearProject
* @url /project/login
* @method POST
* @return void :名称
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \think\Exception
* @throws PDOException
* @author PearProject
* @url /project/login
* @method POST
*/
public function index()
{
@ -92,34 +92,8 @@ class Login extends BasicApi
if (!$mobile) {
$member['password'] !== $data['password'] && $this->error('账号或密码错误', 201);
}
// 更新登录信息
Db::name('Member')->where(['id' => $member['id']])->update([
'last_login_time' => Db::raw('now()'),
]);
$list = MemberAccount::where(['member_code' => $member['code']])->order('id asc')->select()->toArray();
$organizationList = [];
if ($list) {
foreach ($list as $item) {
$organization = Organization::where(['code' => $item['organization_code']])->find();
if ($organization) {
$organizationList[] = $organization;
}
}
}
$member['account_id'] = $list[0]['id'];
$member['is_owner'] = $list[0]['is_owner'];
$member['authorize'] = $list[0]['authorize'];
$member['position'] = $list[0]['position'];
$member['department'] = $list[0]['department'];
setCurrentMember($member);
!empty($member['authorize']) && NodeService::applyProjectAuthNode();
$member = getCurrentMember();
Log::write(json_encode($member), "member-login");
$tokenList = JwtService::initToken($member);
$accessTokenExp = JwtService::decodeToken($tokenList['accessToken'])->exp;
$tokenList['accessTokenExp'] = $accessTokenExp;
$this->success('', ['member' => $member, 'tokenList' => $tokenList, 'organizationList' => $organizationList]);
$result = Member::login($member);
$this->success('', $result);
}
/**
@ -307,15 +281,23 @@ class Login extends BasicApi
}
public function _checkLogin()
{
$loginInfo = session('loginInfo');
$this->success('', $loginInfo);
}
/**
* 退出登录
*/
public function out()
public function _out()
{
session('user') && LogService::write('系统管理', '用户退出系统成功');
session('member') && LogService::write('系统管理', '用户退出系统成功');
!empty($_SESSION) && $_SESSION = [];
[session_unset(), session_destroy()];
$this->success('退出登录成功!');
session('loginInfo', null);
$this->success('');
}
}

View File

@ -27,7 +27,8 @@
"overtrue/easy-sms": "^1.1",
"phpoffice/phpspreadsheet": "^1.5",
"firebase/php-jwt": "^5.0",
"phpmailer/phpmailer": "^6.0"
"phpmailer/phpmailer": "^6.0",
"mingyoung/dingtalk": "2.0"
},
"autoload": {
"psr-4": {

78
config/dingtalk.php Normal file
View File

@ -0,0 +1,78 @@
<?php
return [
/*
|-----------------------------------------------------------
| 【必填】企业 corpId
|-----------------------------------------------------------
*/
'corp_id' => 'ccc',
/*
|-----------------------------------------------------------
| 【必填】应用 AppKey
|-----------------------------------------------------------
*/
'app_key' => 'bbb',
/*
|-----------------------------------------------------------
| 【必填】应用 AppSecret
|-----------------------------------------------------------
*/
'app_secret' => 'aaa',
/*
|-----------------------------------------------------------
| 【选填】加解密
|-----------------------------------------------------------
| 此处的 `token` `aes_key` 用于事件通知的加解密
| 如果你用到事件回调功能,需要配置该两项
*/
'token' => 'uhl3CZbtsmf93bFPanmMenhWwrqbSwPc',
'aes_key' => 'qZEOmHU2qYYk6n6vqLfi3FAhcp9bGA2kgbfnsXDrGgN',
/*
|-----------------------------------------------------------
| 【选填】后台免登配置信息
|-----------------------------------------------------------
| 如果你用到应用管理后台免登功能,需要配置该项
*/
'sso_secret' => 'Fx9_i5dSW5tpGtjalksdf98JF8uj32xb4NJQR5G9-VSchasd98asfdMmLR',
/*
|-----------------------------------------------------------
| 【选填】第三方网站 OAuth 授权
|-----------------------------------------------------------
| 如果你用到扫码登录、钉钉内免登和密码登录第三方网站,需要配置该项
*/
'oauth' => [
/*
|-------------------------------------------
| `app-01` 为你自定义的名称,不要重复即可
|-------------------------------------------
| 数组内需要配置 `client_id`, `client_secret`, `scope` `redirect` 四项
|
| `client_id` 为钉钉登录应用的 `appId`
| `client_secret` 为钉钉登录应用的 `appSecret`
| `scope`:
| - 扫码登录第三方网站和密码登录第三方网站填写 `snsapi_login`
| - 钉钉内免登第三方网站填写 `snsapi_auth`
| `redirect` 为回调地址
*/
'app-01' => [
'client_id' => 'aaa',
'client_secret' => 'bbb-Tu2CsUZN-ZlQXWQ',
'scope' => 'snsapi_login',
'redirect' => 'https://example.com',
],
/*
|-------------------------------------------
| 可配置多个 OAuth 应用,数组内内容同上
|-------------------------------------------
*/
'app-02' => [
// ...
]
]
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB