mirror of https://github.com/tp4a/teleport
temp.
parent
39ced04d25
commit
1db8db69c6
|
@ -829,6 +829,7 @@ $app.create_dlg_edit_host = function () {
|
|||
dlg.dom.edit_router_port.val('' + dlg.field_router_port);
|
||||
}
|
||||
} else {
|
||||
dlg.field_router_ip = '';
|
||||
dlg.field_router_port = 0;
|
||||
}
|
||||
|
||||
|
@ -878,88 +879,6 @@ $app.create_dlg_edit_host = function () {
|
|||
return dlg;
|
||||
};
|
||||
|
||||
$app.create_dlg_host_info = function () {
|
||||
var dlg = {};
|
||||
dlg.dom_id = 'dlg-user-info';
|
||||
dlg.row_id = -1;
|
||||
dlg.need_edit = false;
|
||||
|
||||
dlg.dom = {
|
||||
dialog: $('#' + dlg.dom_id),
|
||||
dlg_title: $('#' + dlg.dom_id + ' [data-field="dlg-title"]'),
|
||||
info: $('#' + dlg.dom_id + ' [data-field="user-info"]'),
|
||||
btn_edit: $('#' + dlg.dom_id + ' [data-field="btn-edit"]')
|
||||
};
|
||||
|
||||
dlg.init = function (cb_stack) {
|
||||
dlg.dom.dialog.on('hidden.bs.modal', function () {
|
||||
if (!dlg.need_edit)
|
||||
return;
|
||||
$app.dlg_edit_user.show_edit(dlg.row_id);
|
||||
});
|
||||
|
||||
dlg.dom.btn_edit.click(function () {
|
||||
dlg.need_edit = true;
|
||||
dlg.dom.dialog.modal('hide');
|
||||
});
|
||||
|
||||
cb_stack.exec();
|
||||
};
|
||||
|
||||
dlg.show = function (row_id) {
|
||||
dlg.row_id = row_id;
|
||||
dlg.need_edit = false;
|
||||
|
||||
var _row_data = $app.table_host.get_row(dlg.row_id);
|
||||
|
||||
// 表格加载时,是不会读取用户的 desc 字段的,因此可以判断此用户是否已经读取过详细信息了
|
||||
if (_.isUndefined(_row_data.desc)) {
|
||||
// 尚未读取,则向服务器要求获取此用户账号的完整信息
|
||||
$tp.ajax_post_json('/user/get-user/' + _row_data.id, {},
|
||||
function (ret) {
|
||||
if (ret.code === TPE_OK) {
|
||||
$app.table_host.update_row(dlg.row_id, ret.data);
|
||||
dlg.show_info(ret.data);
|
||||
} else {
|
||||
$tp.notify_error('无法获取用户详细信息:' + tp_error_msg(ret.code, ret.message));
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$tp.notify_error('网络故障,无法获取用户详细信息!');
|
||||
}
|
||||
);
|
||||
} else {
|
||||
dlg.show_info(_row_data);
|
||||
}
|
||||
};
|
||||
|
||||
dlg.show_info = function (user) {
|
||||
// 更新对话框中显示的信息
|
||||
dlg.dom.dlg_title.html('<i class="fa fa-vcard-o fa-fw"></i> ' + user.surname);
|
||||
|
||||
var info = [];
|
||||
|
||||
var not_set = '<span class="label label-sm label-ignore">未设置</span>';
|
||||
var mobile = (user.mobile.length === 0) ? not_set : user.mobile;
|
||||
var qq = (user.qq.length === 0) ? not_set : user.qq;
|
||||
var wechat = (user.wechat.length === 0) ? not_set : user.wechat;
|
||||
var desc = (user.desc.length === 0) ? not_set : user.desc;
|
||||
info.push('<tr><td class="key">账号:</td><td class="value">' + user.username + '</td></tr>');
|
||||
info.push('<tr><td class="key">姓名:</td><td class="value">' + user.surname + '</td></tr>');
|
||||
info.push('<tr><td class="key">邮箱:</td><td class="value">' + user.email + '</td></tr>');
|
||||
info.push('<tr><td class="key">电话:</td><td class="value">' + mobile + '</td></tr>');
|
||||
info.push('<tr><td class="key">QQ:</td><td class="value">' + qq + '</td></tr>');
|
||||
info.push('<tr><td class="key">微信:</td><td class="value">' + wechat + '</td></tr>');
|
||||
info.push('<tr><td class="key">描述:</td><td class="value"><div style="max-height:80px;overflow:auto;">' + desc + '</div></td></tr>');
|
||||
|
||||
dlg.dom.info.html($(info.join('')));
|
||||
|
||||
dlg.dom.dialog.modal();
|
||||
};
|
||||
|
||||
return dlg;
|
||||
};
|
||||
|
||||
$app.create_dlg_accounts = function () {
|
||||
var dlg = {};
|
||||
dlg.dom_id = 'dlg-accounts';
|
||||
|
|
|
@ -486,7 +486,7 @@ class AppConfig(BaseAppConfig):
|
|||
|
||||
self.sys.login = tp_convert_to_attr_dict(_login)
|
||||
if not self.sys.login.is_exists('session_timeout'):
|
||||
self.sys.login.session_timeout = 30
|
||||
self.sys.login.session_timeout = 60 # 1 hour
|
||||
if not self.sys.login.is_exists('retry'):
|
||||
self.sys.login.retry = 0
|
||||
if not self.sys.login.is_exists('lock_timeout'):
|
||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
|||
import threading
|
||||
|
||||
from app.base.logger import log
|
||||
from app.base.configs import get_cfg
|
||||
|
||||
|
||||
class SessionManager(threading.Thread):
|
||||
|
@ -62,7 +63,8 @@ class SessionManager(threading.Thread):
|
|||
"""
|
||||
|
||||
if expire is None:
|
||||
expire = self.SESSION_EXPIRE
|
||||
# expire = self.SESSION_EXPIRE
|
||||
expire = get_cfg().sys.login.session_timeout * 60
|
||||
|
||||
if expire < 0:
|
||||
with self._lock:
|
||||
|
|
|
@ -9,13 +9,6 @@ TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH = 0x0008 # 用户名+密码+OATH
|
|||
APP_MODE_NORMAL = 1
|
||||
APP_MODE_MAINTENANCE = 2
|
||||
|
||||
# ==========================================================================
|
||||
# 用户账号状态
|
||||
# ==========================================================================
|
||||
USER_STATE_NORMAL = 1 # 正常状态
|
||||
USER_STATE_LOCKED = 2 # 锁定(例如密码连错n次)
|
||||
USER_STATE_DISABLED = 3 # 禁用
|
||||
|
||||
# ==========================================================================
|
||||
# 远程主机账号认证方式
|
||||
# ==========================================================================
|
||||
|
|
|
@ -11,6 +11,7 @@ from app.logic.auth.captcha import tp_captcha_generate_image
|
|||
from app.model import user
|
||||
from app.model import syslog
|
||||
from app.logic.auth.password import tp_password_verify
|
||||
from app.base.utils import tp_timestamp_utc_now
|
||||
|
||||
|
||||
class LoginHandler(TPBaseHandler):
|
||||
|
@ -53,68 +54,86 @@ class LoginHandler(TPBaseHandler):
|
|||
|
||||
class DoLoginHandler(TPBaseJsonHandler):
|
||||
def post(self):
|
||||
sys_cfg = get_cfg().sys
|
||||
|
||||
args = self.get_argument('args', None)
|
||||
if args is not None:
|
||||
try:
|
||||
args = json.loads(args)
|
||||
except:
|
||||
return self.write_json(TPE_JSON_FORMAT, '参数错误')
|
||||
if args is None:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
try:
|
||||
login_type = args['type']
|
||||
captcha = args['captcha'].strip()
|
||||
username = args['username'].strip()
|
||||
password = args['password']
|
||||
oath = args['oath'].strip()
|
||||
remember = args['remember']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM, '参数错误')
|
||||
else:
|
||||
return self.write_json(TPE_PARAM, '参数错误')
|
||||
try:
|
||||
args = json.loads(args)
|
||||
except:
|
||||
return self.write_json(TPE_JSON_FORMAT, '参数错误')
|
||||
|
||||
_tmp = {'username': username, 'surname': username}
|
||||
try:
|
||||
login_type = args['type']
|
||||
captcha = args['captcha'].strip()
|
||||
username = args['username'].strip().lower()
|
||||
password = args['password']
|
||||
oath = args['oath'].strip()
|
||||
remember = args['remember']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
if login_type not in [TP_LOGIN_AUTH_USERNAME_PASSWORD,
|
||||
TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA,
|
||||
TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH,
|
||||
TP_LOGIN_AUTH_USERNAME_OATH
|
||||
]:
|
||||
return self.write_json(TPE_PARAM, '未知的认证方式')
|
||||
|
||||
if login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA:
|
||||
oath = None
|
||||
code = self.get_session('captcha')
|
||||
if code is None:
|
||||
return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效')
|
||||
self.del_session('captcha')
|
||||
if code.lower() != captcha.lower():
|
||||
return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误')
|
||||
elif login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH:
|
||||
elif login_type in [TP_LOGIN_AUTH_USERNAME_OATH, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]:
|
||||
if len(oath) == 0:
|
||||
return self.write_json(TPE_OATH_MISMATCH, '未提供身份验证器动态验证码')
|
||||
else:
|
||||
return self.write_json(TPE_PARAM, '参数错误')
|
||||
|
||||
self.del_session('captcha')
|
||||
|
||||
if len(username) == 0:
|
||||
return self.write_json(TPE_PARAM, '未提供登录用户名')
|
||||
|
||||
err, user_info = user.get_by_username(username)
|
||||
# if user_info is None:
|
||||
# return self.write_json(TPE_USER_AUTH)
|
||||
if err != TPE_OK:
|
||||
if err == TPE_NOT_EXISTS:
|
||||
syslog.sys_log(_tmp, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,用户`{}`不存在'.format(username))
|
||||
syslog.sys_log({'username': username, 'surname': username}, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,用户`{}`不存在'.format(username))
|
||||
return self.write_json(err)
|
||||
|
||||
if user_info['state'] == USER_STATE_LOCKED:
|
||||
syslog.sys_log(_tmp, self.request.remote_ip, TPE_USER_LOCKED, '登录失败,用户已被锁定')
|
||||
return self.write_json(TPE_USER_LOCKED)
|
||||
elif user_info['state'] == USER_STATE_DISABLED:
|
||||
syslog.sys_log(_tmp, self.request.remote_ip, TPE_USER_DISABLED, '登录失败,用户已被禁用')
|
||||
if user_info['state'] == TP_STATE_LOCKED:
|
||||
# 用户已经被锁定,如果系统配置为一定时间后自动解锁,则更新一下用户信息
|
||||
if sys_cfg.login.lock_timeout != 0:
|
||||
if tp_timestamp_utc_now() - user_info.lock_time > sys_cfg.login.lock_timeout * 60:
|
||||
user_info.fail_count = 0
|
||||
user_info.state = TP_STATE_NORMAL
|
||||
if user_info['state'] == TP_STATE_LOCKED:
|
||||
syslog.sys_log(user_info, self.request.remote_ip, TPE_USER_LOCKED, '登录失败,用户已被锁定')
|
||||
return self.write_json(TPE_USER_LOCKED)
|
||||
elif user_info['state'] == TP_STATE_DISABLED:
|
||||
syslog.sys_log(user_info, self.request.remote_ip, TPE_USER_DISABLED, '登录失败,用户已被禁用')
|
||||
return self.write_json(TPE_USER_DISABLED)
|
||||
elif user_info['state'] != USER_STATE_NORMAL:
|
||||
syslog.sys_log(_tmp, self.request.remote_ip, TPE_FAILED, '登录失败,系统内部错误')
|
||||
elif user_info['state'] != TP_STATE_NORMAL:
|
||||
syslog.sys_log(user_info, self.request.remote_ip, TPE_FAILED, '登录失败,系统内部错误')
|
||||
return self.write_json(TPE_FAILED)
|
||||
|
||||
if login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA:
|
||||
err_msg = ''
|
||||
if login_type in [TP_LOGIN_AUTH_USERNAME_PASSWORD, TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]:
|
||||
if not tp_password_verify(password, user_info['password']):
|
||||
syslog.sys_log(_tmp, self.request.remote_ip, TPE_USER_AUTH, '登录失败,密码错误!')
|
||||
err, is_locked = user.update_fail_count(self, user_info)
|
||||
if is_locked:
|
||||
err_msg = '用户被临时锁定!'
|
||||
syslog.sys_log(user_info, self.request.remote_ip, TPE_USER_AUTH, '登录失败,密码错误!{}'.format(err_msg))
|
||||
return self.write_json(TPE_USER_AUTH)
|
||||
elif login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH:
|
||||
elif login_type in [TP_LOGIN_AUTH_USERNAME_OATH, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]:
|
||||
if not tp_oath_verify_code(user_info['oath_secret'], oath):
|
||||
syslog.sys_log(_tmp, self.request.remote_ip, TPE_OATH_MISMATCH, "登录失败,身份验证器动态验证码错误!")
|
||||
err, is_locked = user.update_fail_count(self, user_info)
|
||||
if is_locked:
|
||||
err_msg = '用户被临时锁定!'
|
||||
syslog.sys_log(user_info, self.request.remote_ip, TPE_OATH_MISMATCH, "登录失败,身份验证器动态验证码错误!{}".format(err_msg))
|
||||
return self.write_json(TPE_OATH_MISMATCH)
|
||||
|
||||
self._user = user_info
|
||||
|
@ -122,12 +141,9 @@ class DoLoginHandler(TPBaseJsonHandler):
|
|||
del self._user['password']
|
||||
del self._user['oath_secret']
|
||||
|
||||
print('00000', self._user)
|
||||
|
||||
if remember:
|
||||
self.set_session('user', self._user, 12 * 60 * 60)
|
||||
else:
|
||||
# TODO: 使用系统配置项中的默认会话超时
|
||||
self.set_session('user', self._user)
|
||||
|
||||
user.update_login_info(self, user_info['id'])
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
|
||||
# import hashlib
|
||||
|
||||
from app.const import *
|
||||
from app.base.logger import log
|
||||
# from app.base.configs import get_cfg
|
||||
from app.base.configs import get_cfg
|
||||
from app.base.db import get_db, SQL
|
||||
from app.model import syslog
|
||||
# from app.logic.auth.oath import tp_oath_verify_code
|
||||
# from app.logic.auth.password import tp_password_generate_secret, tp_password_verify
|
||||
from app.base.logger import log
|
||||
from app.base.utils import tp_timestamp_utc_now
|
||||
from app.const import *
|
||||
from app.model import syslog
|
||||
|
||||
|
||||
def get_user_info(user_id):
|
||||
|
@ -32,7 +30,7 @@ def get_user_info(user_id):
|
|||
|
||||
def get_by_username(username):
|
||||
s = SQL(get_db())
|
||||
s.select_from('user', ['id', 'type', 'auth_type', 'username', 'surname', 'password', 'oath_secret', 'role_id', 'state', 'email', 'create_time', 'last_login', 'last_ip', 'last_chpass', 'mobile', 'qq', 'wechat', 'desc'], alt_name='u')
|
||||
s.select_from('user', ['id', 'type', 'auth_type', 'username', 'surname', 'password', 'oath_secret', 'role_id', 'state', 'fail_count', 'lock_time', 'email', 'create_time', 'last_login', 'last_ip', 'last_chpass', 'mobile', 'qq', 'wechat', 'desc'], alt_name='u')
|
||||
s.left_join('role', ['name', 'privilege'], join_on='r.id=u.role_id', alt_name='r', out_map={'name': 'role'})
|
||||
s.where('u.username="{}"'.format(username))
|
||||
err = s.query()
|
||||
|
@ -249,11 +247,10 @@ def set_password(handler, user_id, password):
|
|||
|
||||
|
||||
def update_login_info(handler, user_id):
|
||||
|
||||
db = get_db()
|
||||
_time_now = tp_timestamp_utc_now()
|
||||
|
||||
sql = 'UPDATE `{}user` SET last_login=login_time, last_ip=login_ip, login_time={login_time}, login_ip="{ip}" WHERE id={user_id};' \
|
||||
sql = 'UPDATE `{}user` SET fail_count=0, last_login=login_time, last_ip=login_ip, login_time={login_time}, login_ip="{ip}" WHERE id={user_id};' \
|
||||
''.format(db.table_prefix,
|
||||
login_time=_time_now, ip=handler.request.remote_ip, user_id=user_id
|
||||
)
|
||||
|
@ -285,6 +282,29 @@ def update_users_state(handler, user_ids, state):
|
|||
return TPE_DATABASE
|
||||
|
||||
|
||||
def update_fail_count(handler, user_info):
|
||||
db = get_db()
|
||||
sys_cfg = get_cfg().sys
|
||||
sql_list = []
|
||||
is_locked = False
|
||||
fail_count = user_info.fail_count + 1
|
||||
|
||||
sql = 'UPDATE `{}user` SET fail_count={count} WHERE id={uid};' \
|
||||
''.format(db.table_prefix, count=fail_count, uid=user_info.id)
|
||||
sql_list.append(sql)
|
||||
|
||||
if sys_cfg.login.retry != 0 and fail_count >= sys_cfg.login.retry:
|
||||
is_locked = True
|
||||
sql = 'UPDATE `{}user` SET state={state}, lock_time={lock_time} WHERE id={uid};' \
|
||||
''.format(db.table_prefix, state=TP_STATE_LOCKED, lock_time=tp_timestamp_utc_now(), uid=user_info.id)
|
||||
sql_list.append(sql)
|
||||
|
||||
if db.transaction(sql_list):
|
||||
return TPE_OK, is_locked
|
||||
else:
|
||||
return TPE_DATABASE, is_locked
|
||||
|
||||
|
||||
def remove_users(handler, users):
|
||||
s = SQL(get_db())
|
||||
|
||||
|
@ -587,7 +607,7 @@ def get_group_with_member(sql_filter, sql_order, sql_limit):
|
|||
for g in sg.recorder:
|
||||
g['member_count'] = 0
|
||||
g['members'] = []
|
||||
g['_mid'] = [] # 临时使用,构建此组的前5个成员的id
|
||||
g['_mid'] = [] # 临时使用,构建此组的前5个成员的id
|
||||
|
||||
# 对于本次要返回的用户组,取其中每一个组内成员的基本信息(id/用户名/真实名称等)
|
||||
groups = [g['id'] for g in sg.recorder]
|
||||
|
|
Loading…
Reference in New Issue