mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-07 09:57:37 +00:00
feat: 新增ldap帐号
This commit is contained in:
parent
c9e7fc14a1
commit
b60b572494
@ -4,7 +4,7 @@
|
||||
|
||||
/**
|
||||
* A helper file for Laravel, to provide autocomplete information to your IDE
|
||||
* Generated for Laravel 8.83.16.
|
||||
* Generated for Laravel 8.83.27.
|
||||
*
|
||||
* This file should not be included in your code, only analyzed by your IDE!
|
||||
*
|
||||
@ -2167,6 +2167,17 @@
|
||||
{
|
||||
/** @var \Illuminate\Auth\SessionGuard $instance */
|
||||
return $instance->setRequest($request);
|
||||
}
|
||||
/**
|
||||
* Get the timebox instance used by the guard.
|
||||
*
|
||||
* @return \Illuminate\Support\Timebox
|
||||
* @static
|
||||
*/
|
||||
public static function getTimebox()
|
||||
{
|
||||
/** @var \Illuminate\Auth\SessionGuard $instance */
|
||||
return $instance->getTimebox();
|
||||
}
|
||||
/**
|
||||
* Determine if the current user is authenticated. If not, throw an exception.
|
||||
@ -16109,6 +16120,16 @@
|
||||
{
|
||||
/** @var \Facade\FlareClient\Flare $instance */
|
||||
return $instance->filterExceptionsUsing($filterExceptionsCallable);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static function filterReportsUsing($filterReportsCallable)
|
||||
{
|
||||
/** @var \Facade\FlareClient\Flare $instance */
|
||||
return $instance->filterReportsUsing($filterReportsCallable);
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Ldap\LdapUser;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Models\UserCheckinRecord;
|
||||
@ -10,8 +11,13 @@ use App\Module\BillExport;
|
||||
use App\Module\BillMultipleExport;
|
||||
use Arr;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use Guanguans\Notify\Factory;
|
||||
use Guanguans\Notify\Messages\EmailMessage;
|
||||
use LdapRecord\Auth\PasswordRequiredException;
|
||||
use LdapRecord\Auth\UsernameRequiredException;
|
||||
use LdapRecord\Container;
|
||||
use LdapRecord\LdapRecordException;
|
||||
use Madzipper;
|
||||
use Request;
|
||||
use Response;
|
||||
@ -311,6 +317,74 @@ class SystemController extends AbstractController
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/setting/thirdaccess 04. 第三方帐号(限管理员)
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName setting__thirdaccess
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - save: 保存设置(参数:['ldap_open', 'ldap_host', 'ldap_port', 'ldap_password', 'ldap_cn', 'ldap_dn'])
|
||||
* - testldap: 测试ldap连接
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function setting__thirdaccess()
|
||||
{
|
||||
User::auth('admin');
|
||||
//
|
||||
$type = trim(Request::input('type'));
|
||||
if ($type == 'testldap') {
|
||||
$all = Base::newTrim(Request::input());
|
||||
$connection = Container::getDefaultConnection();
|
||||
try {
|
||||
$connection->setConfiguration([
|
||||
"hosts" => [$all['ldap_host']],
|
||||
"port" => intval($all['ldap_port']),
|
||||
"password" => $all['ldap_password'],
|
||||
"username" => $all['ldap_cn'],
|
||||
"base_dn" => $all['ldap_dn'],
|
||||
]);
|
||||
if ($connection->auth()->attempt($all['ldap_cn'], $all['ldap_password'])) {
|
||||
return Base::retSuccess('验证通过');
|
||||
} else {
|
||||
return Base::retError('验证失败');
|
||||
}
|
||||
} catch (LdapRecordException $e) {
|
||||
return Base::retError($e->getMessage() ?: "验证失败:未知错误", config("ldap.connections.default"));
|
||||
}
|
||||
} elseif ($type == 'save') {
|
||||
if (env("SYSTEM_SETTING") == 'disabled') {
|
||||
return Base::retError('当前环境禁止修改');
|
||||
}
|
||||
$all = Base::newTrim(Request::input());
|
||||
foreach ($all as $key => $value) {
|
||||
if (!in_array($key, [
|
||||
'ldap_open',
|
||||
'ldap_host',
|
||||
'ldap_port',
|
||||
'ldap_password',
|
||||
'ldap_cn',
|
||||
'ldap_dn'
|
||||
])) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
}
|
||||
$all['ldap_port'] = intval($all['ldap_port']) ?: 389;
|
||||
$setting = Base::setting('thirdAccessSetting', Base::newTrim($all));
|
||||
} else {
|
||||
$setting = Base::setting('thirdAccessSetting');
|
||||
}
|
||||
//
|
||||
$setting['ldap_open'] = $setting['ldap_open'] ?: 'close';
|
||||
$setting['ldap_port'] = intval($setting['ldap_port']) ?: 389;
|
||||
//
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/demo 05. 获取演示帐号
|
||||
*
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Ldap\LdapUser;
|
||||
use App\Models\AbstractModel;
|
||||
use App\Models\Meeting;
|
||||
use App\Models\Project;
|
||||
@ -49,6 +50,8 @@ class UsersController extends AbstractController
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据(同"获取我的信息"接口)
|
||||
*
|
||||
* @throws \LdapRecord\Configuration\ConfigurationException
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
@ -89,11 +92,22 @@ class UsersController extends AbstractController
|
||||
$needData = ['code' => $needCode ? 'need' : 'no'];
|
||||
return Base::retError($msg, $needData);
|
||||
};
|
||||
//
|
||||
$user = User::whereEmail($email)->first();
|
||||
$checkPassword = true;
|
||||
if (LdapUser::isOpen() && (empty($user) || in_array('ldap', $user->identity))) {
|
||||
$user = LdapUser::userLogin($email, $password, $user);
|
||||
if ($user) {
|
||||
$identity = array_merge(array_diff($user->identity, ['ldap']), ['ldap']);
|
||||
$user->identity = "," . implode(",", $identity) . ",";
|
||||
$user->save();
|
||||
}
|
||||
$checkPassword = false;
|
||||
}
|
||||
if (empty($user)) {
|
||||
return $retError('帐号或密码错误');
|
||||
}
|
||||
if ($user->password != Base::md52($password, $user->encrypt)) {
|
||||
if ($checkPassword && $user->password != Base::md52($password, $user->encrypt)) {
|
||||
return $retError('帐号或密码错误');
|
||||
}
|
||||
//
|
||||
|
||||
162
app/Ldap/LdapUser.php
Normal file
162
app/Ldap/LdapUser.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ldap;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
use LdapRecord\Container;
|
||||
use LdapRecord\LdapRecordException;
|
||||
use LdapRecord\Models\Model;
|
||||
|
||||
class LdapUser extends Model
|
||||
{
|
||||
protected static bool $init = false;
|
||||
/**
|
||||
* The object classes of the LDAP model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $objectClasses = [
|
||||
'inetOrgPerson',
|
||||
'organizationalPerson',
|
||||
'person',
|
||||
'top',
|
||||
'posixAccount',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return LdapUser
|
||||
*/
|
||||
public static function static(): LdapUser
|
||||
{
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务是否打开
|
||||
* @return bool
|
||||
*/
|
||||
public static function isOpen(): bool
|
||||
{
|
||||
$setting = Base::setting('thirdAccessSetting');
|
||||
return $setting['ldap_open'] === 'open';
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化配置
|
||||
* @return void
|
||||
* @throws \LdapRecord\Configuration\ConfigurationException
|
||||
*/
|
||||
public static function initConfig()
|
||||
{
|
||||
if (self::$init) {
|
||||
return;
|
||||
}
|
||||
self::$init = true;
|
||||
//
|
||||
$setting = Base::setting('thirdAccessSetting');
|
||||
$connection = Container::getDefaultConnection();
|
||||
$connection->setConfiguration([
|
||||
"hosts" => [$setting['ldap_host']],
|
||||
"port" => intval($setting['ldap_port']),
|
||||
"password" => $setting['ldap_password'],
|
||||
"username" => $setting['ldap_cn'],
|
||||
"base_dn" => $setting['ldap_dn'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @param User|null $user
|
||||
* @return User|mixed|null
|
||||
* @throws \LdapRecord\Configuration\ConfigurationException
|
||||
*/
|
||||
public static function userLogin($username, $password, $user = null)
|
||||
{
|
||||
self::initConfig();
|
||||
$row = self::static()
|
||||
->where([
|
||||
'cn' => $username,
|
||||
'userPassword' => $password
|
||||
])->first();
|
||||
if (!$row) {
|
||||
return null;
|
||||
}
|
||||
if ($user) {
|
||||
return $user;
|
||||
}
|
||||
return User::reg($username, Base::generatePassword(32));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
* @param $userid
|
||||
* @param $username
|
||||
* @param $password
|
||||
* @param $description
|
||||
* @return void
|
||||
* @throws \LdapRecord\Configuration\ConfigurationException
|
||||
*/
|
||||
public static function userReg($userid, $username, $password, $description = '')
|
||||
{
|
||||
self::initConfig();
|
||||
try {
|
||||
self::static()->create([
|
||||
'cn' => $username,
|
||||
'gidNumber' => 0,
|
||||
'homeDirectory' => '/home/ldap/dootask/' . env("APP_NAME"),
|
||||
'sn' => $username,
|
||||
'uid' => $username,
|
||||
'uidNumber' => $userid,
|
||||
'userPassword' => $password,
|
||||
'description' => $description,
|
||||
]);
|
||||
} catch (LdapRecordException $e) {
|
||||
throw new ApiException("reg ldap fail: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
* @param $username
|
||||
* @param $array
|
||||
* @return void
|
||||
* @throws \LdapRecord\Configuration\ConfigurationException
|
||||
*/
|
||||
public static function userUpdate($username, $array)
|
||||
{
|
||||
self::initConfig();
|
||||
$row = self::static()
|
||||
->where([
|
||||
'cn' => $username,
|
||||
])->first();
|
||||
try {
|
||||
$row?->update($array);
|
||||
} catch (LdapRecordException $e) {
|
||||
throw new ApiException("update ldap fail: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param $username
|
||||
* @return void
|
||||
* @throws \LdapRecord\Configuration\ConfigurationException
|
||||
*/
|
||||
public static function userDelete($username)
|
||||
{
|
||||
self::initConfig();
|
||||
$row = self::static()
|
||||
->where([
|
||||
'cn' => $username,
|
||||
])->first();
|
||||
try {
|
||||
$row?->delete();
|
||||
} catch (LdapRecordException $e) {
|
||||
throw new ApiException("delete ldap fail: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-simplexml": "*",
|
||||
"directorytree/ldaprecord-laravel": "^2.7",
|
||||
"fideloper/proxy": "^4.4.1",
|
||||
"fruitcake/laravel-cors": "^2.0.4",
|
||||
"guanguans/notify": "^1.21.1",
|
||||
|
||||
73
config/ldap.php
Normal file
73
config/ldap.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default LDAP Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which of the LDAP connections below you wish
|
||||
| to use as your default connection for all LDAP operations. Of
|
||||
| course you may add as many connections you'd like below.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LDAP_CONNECTION', 'default'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| LDAP Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Below you may configure each LDAP connection your application requires
|
||||
| access to. Be sure to include a valid base DN - otherwise you may
|
||||
| not receive any results when performing LDAP search operations.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'default' => [
|
||||
'hosts' => [env('LDAP_HOST', '127.0.0.1')],
|
||||
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
|
||||
'password' => env('LDAP_PASSWORD', 'secret'),
|
||||
'port' => env('LDAP_PORT', 389),
|
||||
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', false),
|
||||
'use_tls' => env('LDAP_TLS', false),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| LDAP Logging
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When LDAP logging is enabled, all LDAP search and authentication
|
||||
| operations are logged using the default application logging
|
||||
| driver. This can assist in debugging issues and more.
|
||||
|
|
||||
*/
|
||||
|
||||
'logging' => env('LDAP_LOGGING', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| LDAP Cache
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| LDAP caching enables the ability of caching search results using the
|
||||
| query builder. This is great for running expensive operations that
|
||||
| may take many seconds to complete, such as a pagination request.
|
||||
|
|
||||
*/
|
||||
|
||||
'cache' => [
|
||||
'enabled' => env('LDAP_CACHE', false),
|
||||
'driver' => env('CACHE_DRIVER', 'file'),
|
||||
],
|
||||
|
||||
];
|
||||
@ -338,6 +338,13 @@ export default {
|
||||
}
|
||||
}))
|
||||
}
|
||||
if (identity.includes("ldap")) {
|
||||
arr.push(h('Tag', {
|
||||
props: {
|
||||
color: 'orange'
|
||||
}
|
||||
}, this.$L('LDAP')))
|
||||
}
|
||||
if (identity.includes("admin")) {
|
||||
arr.push(h('Tag', {
|
||||
props: {
|
||||
|
||||
@ -87,16 +87,6 @@ export default {
|
||||
this.loadIng--;
|
||||
});
|
||||
},
|
||||
|
||||
hoursChange(e, key) {
|
||||
let newNum = e * 10;
|
||||
if (newNum % 5 !== 0) {
|
||||
setTimeout(() => {
|
||||
this.$set(this.formData, key, Math.round(e))
|
||||
})
|
||||
$A.messageError('任务提醒只能是0.5的倍数');
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -133,16 +133,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
hoursChange(e, key) {
|
||||
let newNum = e * 10;
|
||||
if (newNum % 5 !== 0) {
|
||||
setTimeout(() => {
|
||||
this.$set(this.formData, key, Math.round(e))
|
||||
})
|
||||
$A.messageError('任务提醒只能是0.5的倍数');
|
||||
}
|
||||
},
|
||||
|
||||
checkEmailSend() {
|
||||
$A.modalInput({
|
||||
title: "测试邮件",
|
||||
|
||||
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="setting-component-item">
|
||||
<Form ref="formData" :model="formData" :rules="ruleData" label-width="auto" @submit.native.prevent>
|
||||
<div class="block-setting-box">
|
||||
<h3>{{ $L('LDAP') }}</h3>
|
||||
<FormItem :label="$L('启用 LDAP 认证')" prop="ldap_open">
|
||||
<RadioGroup v-model="formData.ldap_open">
|
||||
<Radio label="open">{{ $L('开启') }}</Radio>
|
||||
<Radio label="close">{{ $L('关闭') }}</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<template v-if="formData.ldap_open === 'open'">
|
||||
<FormItem :label="$L('LDAP 地址')" prop="ldap_host">
|
||||
<Input v-model="formData.ldap_host"/>
|
||||
<div class="form-tip">{{$L('如:192.168.1.200')}}</div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('LDAP 端口')" prop="ldap_port">
|
||||
<Input v-model="formData.ldap_port" type="number" :placeholder="`${$L('默认')}: 389`"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('密码')" prop="ldap_password">
|
||||
<Input v-model="formData.ldap_password"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('绑定 CN')" prop="ldap_cn">
|
||||
<Input v-model="formData.ldap_cn"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('绑定 DN')" prop="ldap_dn">
|
||||
<Input v-model="formData.ldap_dn"/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button :loading="testLoad" @click="checkTest">{{ $L('测试链接') }}</Button>
|
||||
</FormItem>
|
||||
</template>
|
||||
</div>
|
||||
</Form>
|
||||
<div class="setting-footer">
|
||||
<Button :loading="loadIng > 0" type="primary" @click="submitForm">{{ $L('提交') }}</Button>
|
||||
<Button :loading="loadIng > 0" @click="resetForm" style="margin-left: 8px">{{ $L('重置') }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SystemThirdAccess",
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
formData: {
|
||||
|
||||
},
|
||||
ruleData: {},
|
||||
|
||||
testLoad: false,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.systemSetting();
|
||||
},
|
||||
|
||||
methods: {
|
||||
submitForm() {
|
||||
this.$refs.formData.validate((valid) => {
|
||||
if (valid) {
|
||||
this.systemSetting(true);
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
resetForm() {
|
||||
this.formData = $A.cloneJSON(this.formDatum_bak);
|
||||
},
|
||||
|
||||
systemSetting(save) {
|
||||
this.loadIng++;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'system/setting/thirdaccess?type=' + (save ? 'save' : 'all'),
|
||||
data: this.formData,
|
||||
}).then(({data}) => {
|
||||
if (save) {
|
||||
$A.messageSuccess('修改成功');
|
||||
}
|
||||
this.formData = data;
|
||||
this.formDatum_bak = $A.cloneJSON(this.formData);
|
||||
}).catch(({msg}) => {
|
||||
if (save) {
|
||||
$A.modalError(msg);
|
||||
}
|
||||
}).finally(_ => {
|
||||
this.loadIng--;
|
||||
});
|
||||
},
|
||||
|
||||
checkTest() {
|
||||
if (this.testLoad) {
|
||||
return
|
||||
}
|
||||
this.testLoad = true
|
||||
this.$store.dispatch("call", {
|
||||
url: 'system/setting/thirdaccess?type=testldap',
|
||||
data: this.formData,
|
||||
}).then(({msg}) => {
|
||||
$A.messageSuccess(msg);
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
}).finally(_ => {
|
||||
this.testLoad = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -19,6 +19,9 @@
|
||||
<TabPane :label="$L('邮件设置')" name="emailSetting">
|
||||
<SystemEmailSetting/>
|
||||
</TabPane>
|
||||
<TabPane :label="$L('认证设置')" name="thirdAccess">
|
||||
<SystemThirdAccess/>
|
||||
</TabPane>
|
||||
<TabPane v-if="appPush" :label="$L('APP推送')" name="appPush">
|
||||
<SystemAppPush/>
|
||||
</TabPane>
|
||||
@ -34,9 +37,11 @@ import SystemEmailSetting from "./components/SystemEmailSetting";
|
||||
import SystemAppPush from "./components/SystemAppPush";
|
||||
import SystemMeeting from "./components/SystemMeeting";
|
||||
import SystemCheckin from "./components/SystemCheckin";
|
||||
import SystemThirdAccess from "./components/SystemThirdAccess";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SystemThirdAccess,
|
||||
SystemCheckin,
|
||||
SystemMeeting,
|
||||
SystemAppPush, SystemColumnTemplate, SystemTaskPriority, SystemSetting, SystemEmailSetting},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user