mirror of https://github.com/openspug/spug
A 增加支持LDAP登录
parent
8d3e274bc4
commit
6fb9430129
|
@ -8,9 +8,10 @@ import json
|
||||||
|
|
||||||
|
|
||||||
class User(models.Model, ModelMixin):
|
class User(models.Model, ModelMixin):
|
||||||
username = models.CharField(max_length=100, unique=True)
|
username = models.CharField(max_length=100)
|
||||||
nickname = models.CharField(max_length=100)
|
nickname = models.CharField(max_length=100)
|
||||||
password_hash = models.CharField(max_length=100) # hashed password
|
password_hash = models.CharField(max_length=100) # hashed password
|
||||||
|
type = models.CharField(max_length=20, default='系统用户')
|
||||||
is_supper = models.BooleanField(default=False)
|
is_supper = models.BooleanField(default=False)
|
||||||
is_active = models.BooleanField(default=True)
|
is_active = models.BooleanField(default=True)
|
||||||
access_token = models.CharField(max_length=32)
|
access_token = models.CharField(max_length=32)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from apps.account.models import User, Role
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
import json
|
import json
|
||||||
|
from libs.ldap import LDAP
|
||||||
|
|
||||||
|
|
||||||
class UserView(View):
|
class UserView(View):
|
||||||
|
@ -30,6 +31,7 @@ class UserView(View):
|
||||||
if error is None:
|
if error is None:
|
||||||
form.password_hash = User.make_password(form.pop('password'))
|
form.password_hash = User.make_password(form.pop('password'))
|
||||||
form.created_by = request.user
|
form.created_by = request.user
|
||||||
|
form.type = '系统用户'
|
||||||
User.objects.create(**form)
|
User.objects.create(**form)
|
||||||
return json_response(error=error)
|
return json_response(error=error)
|
||||||
|
|
||||||
|
@ -134,42 +136,84 @@ class SelfView(View):
|
||||||
def login(request):
|
def login(request):
|
||||||
form, error = JsonParser(
|
form, error = JsonParser(
|
||||||
Argument('username', help='请输入用户名'),
|
Argument('username', help='请输入用户名'),
|
||||||
Argument('password', help='请输入密码')
|
Argument('password', help='请输入密码'),
|
||||||
|
Argument('type')
|
||||||
).parse(request.body)
|
).parse(request.body)
|
||||||
if error is None:
|
if error is None:
|
||||||
user = User.objects.filter(username=form.username).first()
|
user = User.objects.filter(username=form.username)
|
||||||
|
if form.type == 'ldap':
|
||||||
|
u = LDAP()
|
||||||
|
valid = u.valid_user(form.username, form.password)
|
||||||
|
if valid['status']:
|
||||||
|
user = user.filter(type='LDAP').first()
|
||||||
if user:
|
if user:
|
||||||
if not user.is_active:
|
if not user.is_active:
|
||||||
return json_response(error="账户已被禁用")
|
return json_response(error="账户已被系统禁用")
|
||||||
|
if not user.role_id:
|
||||||
|
return json_response(error="LDAP用户角色未分配")
|
||||||
|
|
||||||
|
x_real_ip = request.headers.get('x-real-ip', '')
|
||||||
|
ret = handle_user_info(user, form.username, x_real_ip)
|
||||||
|
return json_response(ret)
|
||||||
|
|
||||||
|
x_real_ip = request.headers.get('x-real-ip', '')
|
||||||
|
form.access_token = uuid.uuid4().hex
|
||||||
|
form.nickname = form.username
|
||||||
|
form.token_expired = time.time() + 8 * 60 * 60
|
||||||
|
form.last_login = human_datetime()
|
||||||
|
form.last_ip = x_real_ip
|
||||||
|
form.type = 'LDAP'
|
||||||
|
form.pop('password')
|
||||||
|
User.objects.create(**form)
|
||||||
|
return json_response({
|
||||||
|
'access_token': form.access_token,
|
||||||
|
'nickname': form.username,
|
||||||
|
'is_supper': False,
|
||||||
|
'has_real_ip': True if x_real_ip else False,
|
||||||
|
'permissions': []
|
||||||
|
})
|
||||||
|
return json_response(error=valid['info'])
|
||||||
|
else:
|
||||||
|
user = user.filter(type='系统用户').first()
|
||||||
|
if user and user.deleted_by is None:
|
||||||
|
if not user.is_active:
|
||||||
|
return json_response(error="账户已被系统禁用")
|
||||||
if user.verify_password(form.password):
|
if user.verify_password(form.password):
|
||||||
cache.delete(form.username)
|
cache.delete(form.username)
|
||||||
x_real_ip = request.headers.get('x-real-ip', '')
|
x_real_ip = request.headers.get('x-real-ip', '')
|
||||||
token_isvalid = user.access_token and len(user.access_token) == 32 and user.token_expired >= time.time()
|
ret = handle_user_info(user, form.username, x_real_ip)
|
||||||
user.access_token = user.access_token if token_isvalid else uuid.uuid4().hex
|
return json_response(ret)
|
||||||
user.token_expired = time.time() + 8 * 60 * 60
|
|
||||||
user.last_login = human_datetime()
|
|
||||||
user.last_ip = x_real_ip
|
|
||||||
user.save()
|
|
||||||
return json_response({
|
|
||||||
'access_token': user.access_token,
|
|
||||||
'nickname': user.nickname,
|
|
||||||
'is_supper': user.is_supper,
|
|
||||||
'has_real_ip': True if x_real_ip else False,
|
|
||||||
'permissions': [] if user.is_supper else user.page_perms
|
|
||||||
})
|
|
||||||
|
|
||||||
value = cache.get_or_set(form.username, 0, 86400)
|
value = cache.get_or_set(form.username, 0, 86400)
|
||||||
if value >= 3:
|
if value >= 3:
|
||||||
if user and user.is_active:
|
if user and user.is_active:
|
||||||
user.is_active = False
|
user.is_active = False
|
||||||
user.save()
|
user.save()
|
||||||
return json_response(error='账户已被禁用')
|
return json_response(error='账户已被系统禁用')
|
||||||
cache.set(form.username, value + 1, 86400)
|
cache.set(form.username, value + 1, 86400)
|
||||||
return json_response(error="用户名或密码错误,连续多次错误账户将会被禁用")
|
return json_response(error="用户名或密码错误,连续多次错误账户将会被禁用")
|
||||||
return json_response(error=error)
|
return json_response(error=error)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_user_info(user, username, x_real_ip):
|
||||||
|
cache.delete(username)
|
||||||
|
token_isvalid = user.access_token and len(user.access_token) == 32 and user.token_expired >= time.time()
|
||||||
|
user.access_token = user.access_token if token_isvalid else uuid.uuid4().hex
|
||||||
|
user.token_expired = time.time() + 8 * 60 * 60
|
||||||
|
user.last_login = human_datetime()
|
||||||
|
user.last_ip = x_real_ip
|
||||||
|
user.save()
|
||||||
|
return {
|
||||||
|
'access_token': user.access_token,
|
||||||
|
'nickname': user.nickname,
|
||||||
|
'is_supper': user.is_supper,
|
||||||
|
'has_real_ip': True if x_real_ip else False,
|
||||||
|
'permissions': [] if user.is_supper else user.page_perms
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
def logout(request):
|
||||||
request.user.token_expired = 0
|
request.user.token_expired = 0
|
||||||
request.user.save()
|
request.user.save()
|
||||||
return json_response()
|
return json_response()
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
|
# Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||||
# Copyright: (c) <spug.dev@gmail.com>
|
# Copyright: (c) <spug.dev@gmail.com>
|
||||||
# Released under the MIT License.
|
# Released under the MIT License.
|
||||||
from django.urls import path
|
# from django.urls import path
|
||||||
|
from django.conf.urls import url
|
||||||
from .views import *
|
from .views import *
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', SettingView.as_view()),
|
url(r'^ldap_test/$', ldap_test),
|
||||||
|
url('', SettingView.as_view()),
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,7 +6,7 @@ from apps.setting.models import Setting
|
||||||
|
|
||||||
|
|
||||||
class AppSetting:
|
class AppSetting:
|
||||||
keys = ('public_key', 'private_key', 'mail_service', 'api_key', 'spug_key')
|
keys = ('public_key', 'private_key', 'mail_service', 'api_key', 'spug_key', 'ldap_service')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@lru_cache(maxsize=64)
|
@lru_cache(maxsize=64)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from django.views.generic import View
|
||||||
from libs import JsonParser, Argument, json_response
|
from libs import JsonParser, Argument, json_response
|
||||||
from apps.setting.utils import AppSetting
|
from apps.setting.utils import AppSetting
|
||||||
from apps.setting.models import Setting
|
from apps.setting.models import Setting
|
||||||
|
import ldap
|
||||||
|
|
||||||
|
|
||||||
class SettingView(View):
|
class SettingView(View):
|
||||||
|
@ -20,3 +21,25 @@ class SettingView(View):
|
||||||
for item in form.data:
|
for item in form.data:
|
||||||
AppSetting.set(**item)
|
AppSetting.set(**item)
|
||||||
return json_response(error=error)
|
return json_response(error=error)
|
||||||
|
|
||||||
|
|
||||||
|
def ldap_test(request):
|
||||||
|
form, error = JsonParser(
|
||||||
|
Argument('server'),
|
||||||
|
Argument('port', type=int),
|
||||||
|
Argument('admin_dn'),
|
||||||
|
Argument('password'),
|
||||||
|
).parse(request.body)
|
||||||
|
if error is None:
|
||||||
|
try:
|
||||||
|
con = ldap.initialize("ldap://{0}:{1}".format(form.server, form.port), bytes_mode=False)
|
||||||
|
con.simple_bind_s(form.admin_dn, form.password)
|
||||||
|
return json_response()
|
||||||
|
except Exception as e:
|
||||||
|
error = eval(str(e))
|
||||||
|
return json_response(error=error['desc'])
|
||||||
|
return json_response(error=error)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||||
|
# Copyright: (c) <spug.dev@gmail.com>
|
||||||
|
# Released under the MIT License.
|
||||||
|
|
||||||
|
import ldap
|
||||||
|
from apps.setting.models import Setting
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class LDAP:
|
||||||
|
def __init__(self):
|
||||||
|
server_info = Setting.objects.exclude(key__in=('public_key', 'private_key')) \
|
||||||
|
.filter(key='ldap_service').first()
|
||||||
|
ldap_info_dict = json.loads(server_info.value)
|
||||||
|
self.server = ldap_info_dict['server']
|
||||||
|
self.port = ldap_info_dict['port']
|
||||||
|
self.rules = ldap_info_dict['rules']
|
||||||
|
self.admin_dn = ldap_info_dict['admin_dn']
|
||||||
|
self.password = ldap_info_dict['password']
|
||||||
|
self.base_dn = ldap_info_dict['base_dn']
|
||||||
|
self.con = ldap.initialize("ldap://{0}:{1}".format(self.server, self.port), bytes_mode=False)
|
||||||
|
try:
|
||||||
|
self.con.simple_bind_s(self.admin_dn, self.password)
|
||||||
|
except Exception as error:
|
||||||
|
self.error = error
|
||||||
|
|
||||||
|
def get_user_info(self, username):
|
||||||
|
try:
|
||||||
|
search_scope = ldap.SCOPE_SUBTREE
|
||||||
|
search_filter_name = self.rules
|
||||||
|
retrieve_attributes = None
|
||||||
|
search_filter = '(' + search_filter_name + "=" + username + ')'
|
||||||
|
ldap_result_id = self.con.search(self.base_dn, search_scope, search_filter, retrieve_attributes)
|
||||||
|
result_type, result_data = self.con.result(ldap_result_id, 0)
|
||||||
|
if result_type == ldap.RES_SEARCH_ENTRY:
|
||||||
|
return {'status': True, 'info': result_data[0][0]}
|
||||||
|
else:
|
||||||
|
return {'status': False, 'info': 'LDAP用户未找到'}
|
||||||
|
except Exception as error:
|
||||||
|
error = eval(str(error))
|
||||||
|
return {'status': False, 'info': error['desc']}
|
||||||
|
|
||||||
|
def valid_user(self, username, password):
|
||||||
|
user = self.get_user_info(username)
|
||||||
|
if user['status']:
|
||||||
|
try:
|
||||||
|
self.con.simple_bind_s(user['info'], password)
|
||||||
|
return {'status': True, 'info': ''}
|
||||||
|
except Exception as error:
|
||||||
|
error = eval(str(error))
|
||||||
|
return {'status': False, 'info': error['desc']}
|
||||||
|
else:
|
||||||
|
return {'status': False, 'info': user['info']}
|
||||||
|
|
|
@ -6,3 +6,4 @@ paramiko==2.6.0
|
||||||
django-redis==4.10.0
|
django-redis==4.10.0
|
||||||
requests==2.22.0
|
requests==2.22.0
|
||||||
GitPython==3.0.8
|
GitPython==3.0.8
|
||||||
|
python-ldap==3.2.0
|
||||||
|
|
|
@ -31,6 +31,7 @@ class LoginIndex extends React.Component {
|
||||||
this.props.form.validateFields((err, formData) => {
|
this.props.form.validateFields((err, formData) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
this.setState({loading: true});
|
this.setState({loading: true});
|
||||||
|
formData['type'] = this.state.loginType;
|
||||||
http.post('/api/account/login/', formData)
|
http.post('/api/account/login/', formData)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data['has_real_ip']) {
|
if (!data['has_real_ip']) {
|
||||||
|
@ -75,7 +76,7 @@ class LoginIndex extends React.Component {
|
||||||
<div className={styles.formContainer}>
|
<div className={styles.formContainer}>
|
||||||
<Tabs classNam={styles.tabs} onTabClick={e => this.setState({loginType: e})}>
|
<Tabs classNam={styles.tabs} onTabClick={e => this.setState({loginType: e})}>
|
||||||
<Tabs.TabPane tab="普通登录" key="default"/>
|
<Tabs.TabPane tab="普通登录" key="default"/>
|
||||||
<Tabs.TabPane disabled tab="LDAP登录" key="ldap"/>
|
<Tabs.TabPane tab="LDAP登录" key="ldap"/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Form>
|
<Form>
|
||||||
<Form.Item className={styles.formItem}>
|
<Form.Item className={styles.formItem}>
|
||||||
|
|
|
@ -34,6 +34,9 @@ class ComTable extends React.Component {
|
||||||
}, {
|
}, {
|
||||||
title: '姓名',
|
title: '姓名',
|
||||||
dataIndex: 'nickname',
|
dataIndex: 'nickname',
|
||||||
|
}, {
|
||||||
|
title: '类型',
|
||||||
|
dataIndex: 'type',
|
||||||
}, {
|
}, {
|
||||||
title: '角色',
|
title: '角色',
|
||||||
dataIndex: 'role_name'
|
dataIndex: 'role_name'
|
||||||
|
|
|
@ -5,12 +5,24 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
|
import { Form} from "antd";
|
||||||
|
import { observer } from 'mobx-react'
|
||||||
|
|
||||||
|
|
||||||
export default function BasicSetting(props) {
|
@observer
|
||||||
|
class BasicSetting extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className={styles.title}>基本设置</div>
|
<div className={styles.title}>基本设置</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
export default Form.create()(BasicSetting)
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||||
|
* Copyright (c) <spug.dev@gmail.com>
|
||||||
|
* Released under the MIT License.
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './index.module.css';
|
||||||
|
import {Button, Form, Input, message} from "antd";
|
||||||
|
import { http } from 'libs';
|
||||||
|
import { observer } from 'mobx-react'
|
||||||
|
import store from './store';
|
||||||
|
import lds from "lodash";
|
||||||
|
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class LDAPSetting extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.setting = JSON.parse(lds.get(store.settings, 'ldap_service.value', "{}"));
|
||||||
|
this.state = {
|
||||||
|
loading: false,
|
||||||
|
ldap_test_loading: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = () => {
|
||||||
|
const formData = [];
|
||||||
|
this.props.form.validateFields((err, data) => {
|
||||||
|
if (!err) {
|
||||||
|
this.setState({loading: true});
|
||||||
|
formData.push({key: 'ldap_service', value: JSON.stringify(data)});
|
||||||
|
http.post('/api/setting/', {data: formData})
|
||||||
|
.then(() => {
|
||||||
|
message.success('保存成功');
|
||||||
|
store.fetchSettings()
|
||||||
|
})
|
||||||
|
.finally(() => this.setState({loading: false}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
ldapTest = () => {
|
||||||
|
this.props.form.validateFields((error, data) => {
|
||||||
|
if (!error) {
|
||||||
|
this.setState({ldap_test_loading: true});
|
||||||
|
http.post('/api/setting/ldap_test/', data).then(()=> {
|
||||||
|
message.success('LDAP服务连接成功')
|
||||||
|
}).finally(()=> this.setState({ldap_test_loading: false}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {getFieldDecorator} = this.props.form;
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className={styles.title}>LDAP设置</div>
|
||||||
|
<Form style={{maxWidth: 400}}>
|
||||||
|
<Form.Item labelCol={{span: 8}} wrapperCol={{span: 16}} required label="LDAP服务地址">
|
||||||
|
{getFieldDecorator('server', {initialValue: this.setting['server'],
|
||||||
|
rules: [{required: true, message: '请输入LDAP服务地址'}]})(
|
||||||
|
<Input placeholder="请输入LDAP服务地址"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item labelCol={{span: 8}} wrapperCol={{span: 16}} required label="LDAP服务端口">
|
||||||
|
{getFieldDecorator('port', {initialValue: this.setting['port'],
|
||||||
|
rules: [{required: true, message: '请输入LDAP服务端口'}]})(
|
||||||
|
<Input placeholder="例如:389"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item labelCol={{span: 8}} wrapperCol={{span: 16}} required label="管理员DN">
|
||||||
|
{getFieldDecorator('admin_dn', {initialValue: this.setting['admin_dn'],
|
||||||
|
rules: [{required: true, message: '请输入LDAP管理员DN'}]})(
|
||||||
|
<Input placeholder="例如:cn=admin,dc=spug,dc=dev"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item labelCol={{span: 8}} wrapperCol={{span: 16}} required label="管理员密码">
|
||||||
|
{getFieldDecorator('password', {initialValue: this.setting['password'],
|
||||||
|
rules: [{required: true, message: '请输入LDAP管理员密码'}]})(
|
||||||
|
<Input.Password placeholder="请输入LDAP管理员密码"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item labelCol={{span: 8}} wrapperCol={{span: 16}} required label="LDAP搜索规则">
|
||||||
|
{getFieldDecorator('rules', {initialValue: this.setting['rules'],
|
||||||
|
rules: [{required: true, message: '请输入LDAP搜索规则'}]})(
|
||||||
|
<Input placeholder="请输入,例如:cn"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item labelCol={{span: 8}} wrapperCol={{span: 16}} required label="基本DN">
|
||||||
|
{getFieldDecorator('base_dn', {initialValue: this.setting['base_dn'],
|
||||||
|
rules: [{required: true, message: '请输入LDAP基本DN'}]})(
|
||||||
|
<Input placeholder="请输入,例如:dc=spug,dc=dev"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="danger" loading={this.state.ldap_test_loading} style={{ marginRight: '10px' }}
|
||||||
|
onClick={this.ldapTest}>测试LDAP</Button>
|
||||||
|
<Button type="primary" loading={this.state.loading} onClick={this.handleSubmit}>保存设置</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Form.create()(LDAPSetting)
|
|
@ -8,6 +8,7 @@ import { Menu } from 'antd';
|
||||||
import {AuthDiv} from 'components';
|
import {AuthDiv} from 'components';
|
||||||
import BasicSetting from './BasicSetting';
|
import BasicSetting from './BasicSetting';
|
||||||
import AlarmSetting from './AlarmSetting';
|
import AlarmSetting from './AlarmSetting';
|
||||||
|
import LDAPSetting from './LDAPSetting';
|
||||||
import OpenService from './OpenService';
|
import OpenService from './OpenService';
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
@ -36,12 +37,14 @@ class Index extends React.Component {
|
||||||
style={{border: 'none'}}
|
style={{border: 'none'}}
|
||||||
onSelect={({selectedKeys}) => this.setState({selectedKeys})}>
|
onSelect={({selectedKeys}) => this.setState({selectedKeys})}>
|
||||||
<Menu.Item key="basic">基本设置</Menu.Item>
|
<Menu.Item key="basic">基本设置</Menu.Item>
|
||||||
|
<Menu.Item key="ldap">LDAP设置</Menu.Item>
|
||||||
<Menu.Item key="alarm">报警服务设置</Menu.Item>
|
<Menu.Item key="alarm">报警服务设置</Menu.Item>
|
||||||
<Menu.Item key="service">开放服务设置</Menu.Item>
|
<Menu.Item key="service">开放服务设置</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.right}>
|
<div className={styles.right}>
|
||||||
{selectedKeys[0] === 'basic' && <BasicSetting />}
|
{selectedKeys[0] === 'basic' && <BasicSetting />}
|
||||||
|
{selectedKeys[0] === 'ldap' && <LDAPSetting />}
|
||||||
{selectedKeys[0] === 'alarm' && <AlarmSetting />}
|
{selectedKeys[0] === 'alarm' && <AlarmSetting />}
|
||||||
{selectedKeys[0] === 'service' && <OpenService />}
|
{selectedKeys[0] === 'service' && <OpenService />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@ class Store {
|
||||||
http.get('/api/setting/')
|
http.get('/api/setting/')
|
||||||
.then(res => {
|
.then(res => {
|
||||||
for (let item of res) {
|
for (let item of res) {
|
||||||
this.settings[item.key] = item
|
this.settings[item.key] = item;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => this.isFetching = false)
|
.finally(() => this.isFetching = false)
|
||||||
|
|
Loading…
Reference in New Issue