添加临时访问授权功能
This commit is contained in:
parent
4fad0b9270
commit
cd5e6e1ec7
|
|
@ -20,6 +20,9 @@ class config_api:
|
|||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getVersion(self):
|
||||
return self.__version
|
||||
|
||||
##### ----- start ----- ###
|
||||
|
||||
# 取面板列表
|
||||
|
|
@ -306,8 +309,83 @@ class config_api:
|
|||
return True
|
||||
return False
|
||||
|
||||
def getVersion(self):
|
||||
return self.__version
|
||||
# 获取临时登录列表
|
||||
def getTempLoginApi(self):
|
||||
if 'tmp_login_expire' in session:
|
||||
return mw.returnJson(False, '没有权限')
|
||||
limit = request.form.get('limit', '10').strip()
|
||||
p = request.form.get('p', '1').strip()
|
||||
tojs = request.form.get('tojs', '').strip()
|
||||
|
||||
tempLoginM = mw.M('temp_login')
|
||||
tempLoginM.where('state=? and expire<?',
|
||||
(0, int(time.time()))).setField('state', -1)
|
||||
|
||||
start = (int(p) - 1) * (int(limit))
|
||||
vlist = tempLoginM.limit(str(start) + ',' + str(limit)).order('id desc').field(
|
||||
'id,addtime,expire,login_time,login_addr,state').select()
|
||||
|
||||
data = {}
|
||||
data['data'] = vlist
|
||||
|
||||
count = tempLoginM.count()
|
||||
page_args = {}
|
||||
page_args['count'] = count
|
||||
page_args['tojs'] = 'get_temp_login'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = limit
|
||||
|
||||
data['page'] = mw.getPage(page_args)
|
||||
return mw.getJson(data)
|
||||
|
||||
# 删除临时登录
|
||||
def removeTempLoginApi(self):
|
||||
if 'tmp_login_expire' in session:
|
||||
return mw.returnJson(False, '没有权限')
|
||||
sid = request.form.get('id', '10').strip()
|
||||
if mw.M('temp_login').where('id=?', (sid,)).delete():
|
||||
mw.writeLog('面板设置', '删除临时登录连接')
|
||||
return mw.returnJson(True, '删除成功')
|
||||
return mw.returnJson(False, '删除失败')
|
||||
|
||||
def setTempLoginApi(self):
|
||||
if 'tmp_login_expire' in session:
|
||||
return mw.returnJson(False, '没有权限')
|
||||
s_time = int(time.time())
|
||||
mw.M('temp_login').where(
|
||||
'state=? and expire>?', (0, s_time)).delete()
|
||||
token = mw.getRandomString(48)
|
||||
salt = mw.getRandomString(12)
|
||||
|
||||
pdata = {
|
||||
'token': mw.md5(token + salt),
|
||||
'salt': salt,
|
||||
'state': 0,
|
||||
'login_time': 0,
|
||||
'login_addr': '',
|
||||
'expire': s_time + 3600,
|
||||
'addtime': s_time
|
||||
}
|
||||
|
||||
if not mw.M('temp_login').count():
|
||||
pdata['id'] = 101
|
||||
|
||||
if mw.M('temp_login').insert(pdata):
|
||||
mw.writeLog('面板设置', '生成临时连接,过期时间:{}'.format(
|
||||
mw.formatDate(times=pdata['expire'])))
|
||||
return mw.getJson({'status': True, 'msg': "临时连接已生成", 'token': token, 'expire': pdata['expire']})
|
||||
return mw.returnJson(False, '连接生成失败')
|
||||
|
||||
def getTempLoginLogsApi(self):
|
||||
if 'tmp_login_expire' in session:
|
||||
return mw.returnJson(False, '没有权限')
|
||||
|
||||
logs_id = request.form.get('id', '').strip()
|
||||
logs_id = int(logs_id)
|
||||
data = mw.M('logs').where(
|
||||
'uid=?', (logs_id,)).order('id desc').field(
|
||||
'id,type,uid,log,addtime').select()
|
||||
return mw.returnJson(False, 'ok', data)
|
||||
|
||||
def get(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -213,6 +213,29 @@ class Sql():
|
|||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
# 插入数据
|
||||
def insert(self, pdata):
|
||||
if not pdata:
|
||||
return False
|
||||
keys, param = self.__format_pdata(pdata)
|
||||
return self.add(keys, param)
|
||||
|
||||
# 更新数据
|
||||
def update(self, pdata):
|
||||
if not pdata:
|
||||
return False
|
||||
keys, param = self.__format_pdata(pdata)
|
||||
return self.save(keys, param)
|
||||
|
||||
# 构造数据
|
||||
def __format_pdata(self, pdata):
|
||||
keys = pdata.keys()
|
||||
keys_str = ','.join(keys)
|
||||
param = []
|
||||
for k in keys:
|
||||
param.append(pdata[k])
|
||||
return keys_str, tuple(param)
|
||||
|
||||
def checkInput(self, data):
|
||||
if not data:
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -392,10 +392,13 @@ def writeLog(stype, msg, args=()):
|
|||
import time
|
||||
import db
|
||||
import json
|
||||
from flask import session
|
||||
uid = 1
|
||||
if 'uid' in session:
|
||||
uid = session['uid']
|
||||
sql = db.Sql()
|
||||
mdate = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
wmsg = getInfo(msg, args)
|
||||
uid = 1
|
||||
data = (stype, wmsg, uid, mdate)
|
||||
result = sql.table('logs').add('type,log,uid,addtime', data)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ CREATE TABLE IF NOT EXISTS `logs` (
|
|||
`uid` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
ALTER TABLE `logs` ADD COLUMN `uid` INTEGER DEFAULT '1';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sites` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ socketio.init_app(app)
|
|||
# http_server.serve_forever()
|
||||
|
||||
# debug macosx dev
|
||||
if mw.isAppleSystem():
|
||||
if mw.isDebugMode():
|
||||
app.debug = True
|
||||
app.config.version = app.config.version + str(time.time())
|
||||
|
||||
|
|
@ -84,6 +84,33 @@ import common
|
|||
common.init()
|
||||
|
||||
|
||||
# ---------- error function start -----------------
|
||||
def getErrorNum(key, limit=None):
|
||||
key = mw.md5(key)
|
||||
num = cache.get(key)
|
||||
if not num:
|
||||
num = 0
|
||||
if not limit:
|
||||
return num
|
||||
if limit > num:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def setErrorNum(key, empty=False, expire=3600):
|
||||
key = mw.md5(key)
|
||||
num = cache.get(key)
|
||||
if not num:
|
||||
num = 0
|
||||
else:
|
||||
if empty:
|
||||
cache.delete(key)
|
||||
return True
|
||||
cache.set(key, num + 1, expire)
|
||||
return True
|
||||
# ---------- error function end -----------------
|
||||
|
||||
|
||||
def funConvert(fun):
|
||||
block = fun.split('_')
|
||||
func = block[0]
|
||||
|
|
@ -98,6 +125,7 @@ def isLogined():
|
|||
if 'login' in session and 'username' in session and session['login'] == True:
|
||||
userInfo = mw.M('users').where(
|
||||
"id=?", (1,)).field('id,username,password').find()
|
||||
# print(userInfo)
|
||||
if userInfo['username'] != session['username']:
|
||||
return False
|
||||
|
||||
|
|
@ -291,6 +319,46 @@ def admin_safe_path(path, req, data, pageFile):
|
|||
return render_template(req + '.html', data=data)
|
||||
|
||||
|
||||
def login_temp_user(token):
|
||||
print(token)
|
||||
if len(token) != 48:
|
||||
return '错误的参数!'
|
||||
|
||||
skey = mw.getClientIp() + '_temp_login'
|
||||
if not getErrorNum(skey, 10):
|
||||
return '连续10次验证失败,禁止1小时'
|
||||
|
||||
stime = int(time.time())
|
||||
data = mw.M('temp_login').where('state=? and expire>?',
|
||||
(0, stime)).field('id,token,salt,expire').find()
|
||||
if not data:
|
||||
setErrorNum(skey)
|
||||
return '验证失败!'
|
||||
|
||||
r_token = mw.md5(token + data['salt'])
|
||||
if r_token != data['token']:
|
||||
setErrorNum(skey)
|
||||
return '验证失败!'
|
||||
|
||||
userInfo = mw.M('users').where(
|
||||
"id=?", (1,)).field('id,username').find()
|
||||
session['login'] = True
|
||||
session['username'] = userInfo['username']
|
||||
session['tmp_login'] = True
|
||||
session['tmp_login_id'] = str(data['id'])
|
||||
session['tmp_login_expire'] = time.time() + 3600
|
||||
session['uid'] = data['id']
|
||||
|
||||
login_addr = mw.getClientIp() + ":" + str(request.environ.get('REMOTE_PORT'))
|
||||
mw.writeLog('用户登录', "登录成功,帐号:{1},登录IP:{2}",
|
||||
(userInfo['username'], login_addr))
|
||||
mw.M('temp_login').where('id=?', (data['id'],)).update(
|
||||
{"login_time": stime, 'state': 1, 'login_addr': login_addr})
|
||||
|
||||
print(session)
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@app.route('/<reqClass>/<reqAction>', methods=['POST', 'GET'])
|
||||
@app.route('/<reqClass>/', methods=['POST', 'GET'])
|
||||
@app.route('/<reqClass>', methods=['POST', 'GET'])
|
||||
|
|
@ -312,11 +380,18 @@ def index(reqClass=None, reqAction=None, reqData=None):
|
|||
pageFile = ('config', 'control', 'crontab', 'files', 'firewall',
|
||||
'index', 'plugins', 'login', 'system', 'site', 'ssl', 'task', 'soft')
|
||||
|
||||
if reqClass == 'login':
|
||||
token = request.args.get('tmp_token', '').strip()
|
||||
print(token)
|
||||
if token != '':
|
||||
return login_temp_user(token)
|
||||
|
||||
# 设置了安全路径
|
||||
ainfo = get_admin_safe()
|
||||
|
||||
# 登录页
|
||||
if reqClass == 'login':
|
||||
|
||||
dologin = request.args.get('dologin', '')
|
||||
if dologin == 'True':
|
||||
session.clear()
|
||||
|
|
|
|||
|
|
@ -338,3 +338,178 @@ function savePanelSSL(){
|
|||
},'json');
|
||||
}
|
||||
|
||||
|
||||
function removeTempAccess(id){
|
||||
$.post('/config/remove_temp_login', {id:id}, function(rdata){
|
||||
showMsg(rdata.msg, function(){
|
||||
setTempAccessReq();
|
||||
},{ icon: rdata.status ? 1 : 2 }, 2000);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function getTempAccessLogsReq(id){
|
||||
$.post('/config/get_temp_login_logs', {id:id}, function(rdata){
|
||||
var tbody = '';
|
||||
for (var i = 0; i < rdata.data.length; i++) {
|
||||
|
||||
tbody += '<tr>';
|
||||
tbody += '<td>' + (rdata.data[i]['type']) +'</td>';
|
||||
tbody += '<td>' + rdata.data[i]['addtime'] +'</td>';
|
||||
tbody += '<td>'+ rdata.data[i]['log'] +'</td>';
|
||||
tbody += '</tr>';
|
||||
}
|
||||
$('#logs_list').html(tbody);
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
function getTempAccessLogs(id){
|
||||
|
||||
layer.open({
|
||||
area: ['700px', '250px'],
|
||||
title: '临时授权管理',
|
||||
closeBtn:1,
|
||||
shift: 0,
|
||||
type: 1,
|
||||
content: "<div class=\"pd20\">\
|
||||
<button class=\"btn btn-success btn-sm refresh_log\">刷新日志</button>\
|
||||
<div class=\"divtable mt10\">\
|
||||
<table class=\"table table-hover\">\
|
||||
<thead>\
|
||||
<tr><th>操作类型</th><th>操作时间</th><th>日志</th></tr>\
|
||||
</thead>\
|
||||
<tbody id=\"logs_list\"></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>",
|
||||
success:function(){
|
||||
getTempAccessLogsReq(id);
|
||||
$('.refresh_log').click(function(){
|
||||
getTempAccessLogsReq(id);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setTempAccessReq(page){
|
||||
if (typeof(page) == 'undefined'){
|
||||
page = 1;
|
||||
}
|
||||
|
||||
$.post('/config/get_temp_login', {page:page}, function(rdata){
|
||||
if ( typeof(rdata.status) !='undefined' && !rdata.status){
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.closeAll();
|
||||
},{icon:2}, 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
var tbody = '';
|
||||
for (var i = 0; i < rdata.data.length; i++) {
|
||||
|
||||
tbody += '<tr>';
|
||||
tbody += '<td>' + (rdata.data[i]['login_addr']||'未登陆') +'</td>';
|
||||
|
||||
tbody += '<td>';
|
||||
switch (parseInt(rdata.data[i]['state'])) {
|
||||
case 0:
|
||||
tbody += '<a style="color:green;">待使用</a>';
|
||||
break;
|
||||
case 1:
|
||||
tbody += '<a style="color:brown;">已使用</a>';
|
||||
break;
|
||||
case -1:
|
||||
tbody += '<a>已过期</a>';
|
||||
break;
|
||||
}
|
||||
tbody += '</td>';
|
||||
|
||||
tbody += '<td>' + (getLocalTime(rdata.data[i]['login_time'])||'未登陆') +'</td>';
|
||||
tbody += '<td>' + getLocalTime(rdata.data[i]['expire']) +'</td>';
|
||||
|
||||
tbody += '<td>';
|
||||
|
||||
if (rdata.data[i]['state'] == '1' ){
|
||||
tbody += '<a class="btlink" onclick="getTempAccessLogs(\''+rdata.data[i]['id']+'\')">操作日志</a>';
|
||||
} else{
|
||||
tbody += '<a class="btlink" onclick="removeTempAccess(\''+rdata.data[i]['id']+'\')">删除</a>';
|
||||
}
|
||||
|
||||
tbody += '</td>';
|
||||
|
||||
tbody += '</tr>';
|
||||
}
|
||||
|
||||
$('#temp_login_view_tbody').html(tbody);
|
||||
$('.temp_login_view_page').html(rdata.page);
|
||||
},'json');
|
||||
}
|
||||
|
||||
function setTempAccess(){
|
||||
layer.open({
|
||||
area: ['700px', '250px'],
|
||||
title: '临时授权管理',
|
||||
closeBtn:1,
|
||||
shift: 0,
|
||||
type: 1,
|
||||
content: "<div class=\"login_view_table pd20\">\
|
||||
<button class=\"btn btn-success btn-sm create_temp_login\" >临时访问授权</button>\
|
||||
<div class=\"divtable mt10\">\
|
||||
<table class=\"table table-hover\">\
|
||||
<thead>\
|
||||
<tr><th>登录IP</th><th>状态</th><th>登录时间</th><th>过期时间</th><th style=\"text-align:right;\">操作</th></tr>\
|
||||
</thead>\
|
||||
<tbody id=\"temp_login_view_tbody\"></tbody>\
|
||||
</table>\
|
||||
<div class=\"temp_login_view_page page\"></div>\
|
||||
</div>\
|
||||
</div>",
|
||||
success:function(){
|
||||
setTempAccessReq();
|
||||
|
||||
$('.create_temp_login').click(function(){
|
||||
layer.confirm('<span style="color:red">注意1:滥用临时授权可能导致安全风险。</br>注意2:请勿在公共场合发布临时授权连接</span></br>即将创建临时授权连接,继续吗?',
|
||||
{
|
||||
title:'风险提示',
|
||||
closeBtn:1,
|
||||
icon:13,
|
||||
}, function(create_temp_login_layer) {
|
||||
$.post('/config/set_temp_login', {}, function(rdata){
|
||||
layer.close(create_temp_login_layer);
|
||||
setTempAccessReq();
|
||||
layer.open({
|
||||
area: '570px',
|
||||
title: '创建临时授权',
|
||||
shift: 0,
|
||||
type: 1,
|
||||
content: "<div class=\"bt-form create_temp_view pd15\">\
|
||||
<div class=\"line\">\
|
||||
<span class=\"tname\">临时授权地址</span>\
|
||||
<div>\
|
||||
<textarea id=\"temp_link\" class=\"bt-input-text mr20\" style=\"margin: 0px;width: 500px;height: 50px;line-height: 19px;\"></textarea>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class=\"line\"><button type=\"submit\" class=\"btn btn-success btn-sm btn-copy-temp-link\" data-clipboard-text=\"\">复制地址</button></div>\
|
||||
<ul class=\"help-info-text c7 ptb15\">\
|
||||
<li>临时授权生成后1小时内使用有效,为一次性授权,使用后立即失效</li>\
|
||||
<li>使用临时授权登录面板后1小时内拥有面板所有权限,请勿在公共场合发布临时授权连接</li>\
|
||||
<li>授权连接信息仅在此处显示一次,若在使用前忘记,请重新生成</li>\
|
||||
</ul>\
|
||||
</div>",
|
||||
success:function(){
|
||||
var temp_link = "".concat(location.origin, "/login?tmp_token=").concat(rdata.token);
|
||||
$('#temp_link').val(temp_link);
|
||||
|
||||
copyText(temp_link);
|
||||
$('.btn-copy-temp-link').click(function(){
|
||||
copyText(temp_link);
|
||||
});
|
||||
}
|
||||
});
|
||||
},'json');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -616,20 +616,19 @@ function divcenter() {
|
|||
$(".layui-layer").css("top", e + "px")
|
||||
}
|
||||
|
||||
function btcopy(password) {
|
||||
$("#bt_copys").attr('data-clipboard-text',password);
|
||||
$("#bt_copys").click();
|
||||
function copyText(value) {
|
||||
var clipboard = new ClipboardJS('#bt_copys');
|
||||
clipboard.on('success', function (e) {
|
||||
layer.msg('复制成功',{icon:1,time:2000});
|
||||
});
|
||||
|
||||
clipboard.on('error', function (e) {
|
||||
layer.msg('复制失败,浏览器不兼容!',{icon:2,time:2000});
|
||||
});
|
||||
$("#bt_copys").attr('data-clipboard-text',value);
|
||||
$("#bt_copys").click();
|
||||
}
|
||||
|
||||
var clipboard = new ClipboardJS('#bt_copys');
|
||||
clipboard.on('success', function (e) {
|
||||
layer.msg('复制成功!',{icon:1});
|
||||
});
|
||||
|
||||
clipboard.on('error', function (e) {
|
||||
layer.msg('复制失败,浏览器不兼容!',{icon:2});
|
||||
});
|
||||
|
||||
function isChineseChar(b) {
|
||||
var a = /[\u4E00-\u9FA5\uF900-\uFA2D]/;
|
||||
return a.test(b)
|
||||
|
|
|
|||
|
|
@ -2220,26 +2220,26 @@ html .menu .menu_exit:hover {
|
|||
margin-left: -40px;
|
||||
vertical-align: 0;
|
||||
position: relative;
|
||||
z-index: 10
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.setting-con p .set-info {
|
||||
margin-left: 20px
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.set-submit {
|
||||
margin: 20px 0 10px 100px
|
||||
margin: 20px 0 10px 100px;
|
||||
}
|
||||
|
||||
.changepath {
|
||||
height: 500px
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.changepath .path-top {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
padding-left: 10px;
|
||||
border-bottom: #aaa 1px solid
|
||||
border-bottom: #aaa 1px solid;
|
||||
}
|
||||
|
||||
.changepath .path-top .btn {
|
||||
|
|
|
|||
|
|
@ -50,9 +50,7 @@
|
|||
<h3 class="f16">设置</h3>
|
||||
</div>
|
||||
<div class="info-title-tips" style="margin: 20px 30px 0px;">
|
||||
<p>
|
||||
<span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;">
|
||||
</span>为了提高安全,请修改别名、默认端口、面板用户和密码!</p>
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>为了提高安全,修改面板密码!</p>
|
||||
</div>
|
||||
<div class="setting-con pd15">
|
||||
<form id="set_config">
|
||||
|
|
@ -67,7 +65,8 @@
|
|||
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right">安全入口</span>
|
||||
<input id="admin_path" name="admin_path" class="inputtxt bt-input-text disable" type="text" value="{{data['admin_path']}}"><span class="modify btn btn-xs btn-success" onclick="modifyAuthPath();">修改</span>
|
||||
<input id="admin_path" name="admin_path" class="inputtxt bt-input-text disable" type="text" value="{{data['admin_path']}}">
|
||||
<button type="button" class="btn btn-success btn-sm ml5" onclick="modifyAuthPath()">设置</button>
|
||||
<span class="set-info c7">面板管理入口,设置后只能通过指定安全入口登录面板,如: /abc</span>
|
||||
</p>
|
||||
|
||||
|
|
@ -99,19 +98,37 @@
|
|||
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right" title="服务器时间">服务器时间</span>
|
||||
<input id="systemdate" name="systemdate" class="inputtxt bt-input-text disable" type="text" value="{{data['systemdate']}}"><span class="modify btn btn-xs btn-success" onclick="syncDate()">同步</span>
|
||||
<input id="systemdate" name="systemdate" class="inputtxt bt-input-text disable" type="text" value="{{data['systemdate']}}">
|
||||
<button type="button" class="btn btn-success btn-sm ml5" onclick="syncDate()">同步</button>
|
||||
<span class="set-info c7">同步当前服务器时间</span>
|
||||
</p>
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right" title="面板用户">面板用户</span>
|
||||
<input name="username_" class="inputtxt bt-input-text disable" type="text" value="{{data['username']}}" disabled><span class="modify btn btn-xs btn-success" onclick="setUserName()">修改</span>
|
||||
<input name="username_" class="inputtxt bt-input-text disable" type="text" value="{{data['username']}}" disabled>
|
||||
<button type="button" class="btn btn-success btn-sm ml5" onclick="setUserName()">设置</button>
|
||||
<span class="set-info c7">设置面板账号</span>
|
||||
</p>
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right" title="面板密码">面板密码</span>
|
||||
<input name="password_" class="inputtxt bt-input-text disable" type="text" value="******" disabled><span class="modify btn btn-xs btn-success" onclick="setPassword()">修改</span>
|
||||
<input name="password_" class="inputtxt bt-input-text disable" type="text" value="******" disabled>
|
||||
<button type="button" class="btn btn-success btn-sm ml5" onclick="setPassword()">设置</button>
|
||||
<span class="set-info c7">设置面板密码</span>
|
||||
</p>
|
||||
</form>
|
||||
<div class="bt-submit set-submit">保存</div>
|
||||
</div>
|
||||
|
||||
<div class="title c6 plr15">
|
||||
<h3 class="f16">安全</h3>
|
||||
</div>
|
||||
|
||||
<div class="setting-con pd15">
|
||||
<p class="mtb15">
|
||||
<span class="set-tit text-right" title="临时访问授权">临时访问授权</span>
|
||||
<button type="button" class="btn btn-success btn-sm ml5" onclick="setTempAccess()">临时访问授权管理</button>
|
||||
<span class="set-info c7">为非管理员临时提供面板访问权限</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ export PATH
|
|||
export LANG=en_US.UTF-8
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
localedef -v -c -i en_US -f UTF-8 en_US.UTF-8
|
||||
|
||||
if grep -Eq "Ubuntu" /etc/*-release; then
|
||||
sudo ln -sf /bin/bash /bin/sh
|
||||
#sudo dpkg-reconfigure dash
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ export PATH
|
|||
export LANG=en_US.UTF-8
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
localedef -v -c -i en_US -f UTF-8 en_US.UTF-8
|
||||
|
||||
if grep -Eq "Ubuntu" /etc/*-release; then
|
||||
sudo ln -sf /bin/bash /bin/sh
|
||||
#sudo dpkg-reconfigure dash
|
||||
|
|
|
|||
Loading…
Reference in New Issue