mirror of https://github.com/tp4a/teleport
用户自行找回密码流程走通,测试通过。客户端弱密码检测功能实现了,服务端的弱密码检测功能还需要实现。
parent
04cc466ea2
commit
05297ec5e5
File diff suppressed because one or more lines are too long
|
@ -72,7 +72,6 @@ $app.on_init = function (cb_stack) {
|
|||
$app.dom.area_captcha.slideUp(100);
|
||||
});
|
||||
|
||||
|
||||
$app.dom.btn_login.click($app.login_account);
|
||||
|
||||
$app.dom.captcha_image.click(function () {
|
||||
|
@ -173,13 +172,12 @@ $app.login_account = function () {
|
|||
$app.do_account_login(str_username, str_password, str_captcha, str_oath, is_remember);
|
||||
}
|
||||
else {
|
||||
$app.dom.btn_login.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', tp_error_msg(ret.code, ret.message));
|
||||
$app.dom.captcha_image.attr('src', '/auth/captcha?h=36&rnd=' + Math.random());
|
||||
$app.dom.input_captcha.focus().select().val('');
|
||||
}
|
||||
|
||||
$app.dom.btn_login.removeAttr('disabled');
|
||||
},
|
||||
function () {
|
||||
$app.hide_op_box();
|
||||
|
@ -232,9 +230,9 @@ $app.init_blur_bg = function () {
|
|||
};
|
||||
|
||||
$app._update_blur_bg = function () {
|
||||
for(;;) {
|
||||
for (; ;) {
|
||||
var img_id = Math.floor(Math.random() * (BLUR_BG_IMG.length));
|
||||
if(img_id !== $app.last_img_idx) {
|
||||
if (img_id !== $app.last_img_idx) {
|
||||
$app.last_img_idx = img_id;
|
||||
break;
|
||||
}
|
||||
|
@ -251,9 +249,9 @@ $app.init_slogan = function () {
|
|||
};
|
||||
|
||||
$app._update_slogan = function () {
|
||||
for(;;) {
|
||||
for (; ;) {
|
||||
var msg_id = Math.floor(Math.random() * (SLOGAN.length));
|
||||
if(msg_id !== $app.last_slogan_idx) {
|
||||
if (msg_id !== $app.last_slogan_idx) {
|
||||
$app.last_slogan_idx = msg_id;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
$tp.notify_error = function (message_, title_) {
|
||||
$tp.notify_error = function (message_, title_, timeout_) {
|
||||
var _title = title_ || '';
|
||||
var _t = timeout_ || 15000;
|
||||
$.gritter.add({
|
||||
//sticky:true,
|
||||
class_name: 'gritter-error',
|
||||
time: 10000,
|
||||
time: _t,
|
||||
title: '<i class="fa fa-warning fa-fw"></i> 错误:' + _title,
|
||||
text: message_
|
||||
});
|
||||
|
|
|
@ -169,6 +169,7 @@ function tp_format_datetime(timestamp, format) {
|
|||
}
|
||||
|
||||
var base64KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
function tp_base64_encode(input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3 = "";
|
||||
|
@ -236,6 +237,7 @@ function tp_get_file_name(path) {
|
|||
}
|
||||
|
||||
var g_unique_id = (new Date()).valueOf();
|
||||
|
||||
function tp_generate_id() {
|
||||
return g_unique_id++;
|
||||
}
|
||||
|
@ -251,6 +253,7 @@ function htmlEncode(_s) {
|
|||
s = s.replace(/\"/g, """);
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
///*2.用正则表达式实现html解码*/
|
||||
//function htmlDecode(_s) {
|
||||
|
@ -274,11 +277,35 @@ function tp_sleep4debug(duration) {
|
|||
// 获取长度为len的随机字符串
|
||||
function tp_gen_random_string(len) {
|
||||
len = len || 32;
|
||||
var _chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; // 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
|
||||
var _chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; // 默认去掉了容易混淆的字符oO,Ll,9gq,Vv,Uu,I1
|
||||
var max_pos = _chars.length;
|
||||
var ret = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
ret += _chars.charAt(Math.floor(Math.random() * max_pos));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// 弱密码检测
|
||||
function tp_check_strong_password(p) {
|
||||
var s = 0;
|
||||
if (p.length < 8)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < p.length; ++i) {
|
||||
var c = p.charCodeAt(i);
|
||||
if (c >= 48 && c <= 57) // 数字
|
||||
s |= 1;
|
||||
else if (c >= 65 && c <= 90) // 大写字母
|
||||
s |= 2;
|
||||
else if (c >= 97 && c <= 122) // 小写字母
|
||||
s |= 4;
|
||||
else
|
||||
s |= 8;
|
||||
}
|
||||
|
||||
if((s&1) && (s&2) && (s&4))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,62 +5,262 @@ $app.on_init = function (cb_stack) {
|
|||
title: $('#title'),
|
||||
icon_bg: $('#icon-bg'),
|
||||
|
||||
err_area: $('#error-area'),
|
||||
err_message: $('#err-message'),
|
||||
err_actions: $('#err-actions'),
|
||||
op_message: null,
|
||||
|
||||
find_password_area: $('#find-my-password'),
|
||||
username: $('#username'),
|
||||
email: $('#email'),
|
||||
captcha_image: $('#captcha-image'),
|
||||
captcha: $('#captcha'),
|
||||
btn_send_email: $('#btn-send-email'),
|
||||
send_result:$('#send-result'),
|
||||
error: {
|
||||
area: $('#area-error'),
|
||||
message: $('#area-error [data-field="message"]')
|
||||
},
|
||||
|
||||
password_area: $('#password-area')
|
||||
find: {
|
||||
area: $('#area-find-password'),
|
||||
captcha_image: $('#area-find-password [data-field="captcha-image"]'),
|
||||
input_username: $('#area-find-password [data-field="input-username"]'),
|
||||
input_email: $('#area-find-password [data-field="input-email"]'),
|
||||
input_captcha: $('#area-find-password [data-field="input-captcha"]'),
|
||||
btn_submit: $('#area-find-password [data-field="btn-submit"]'),
|
||||
message: $('#area-find-password [data-field="message"]')
|
||||
},
|
||||
|
||||
set_password: {
|
||||
area: $('#area-set-password'),
|
||||
info: $('#area-set-password [data-field="info"]'),
|
||||
input_password: $('#area-set-password [data-field="input-password"]'),
|
||||
btn_switch_password: $('#area-set-password [data-field="btn-switch-password"]'),
|
||||
btn_switch_password_icon: $('#area-set-password [data-field="btn-switch-password"] i'),
|
||||
btn_submit: $('#area-set-password [data-field="btn-submit"]'),
|
||||
message: $('#area-set-password [data-field="message"]')
|
||||
}
|
||||
};
|
||||
|
||||
$app.dom.captcha_image.click(function () {
|
||||
$app.dom.find.captcha_image.click(function () {
|
||||
$(this).attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
$app.dom.captcha.focus().val('');
|
||||
$app.dom.find.input_captcha.focus().val('');
|
||||
});
|
||||
|
||||
$app.dom.btn_send_email.click(function() {
|
||||
$app.on_send_email();
|
||||
$app.dom.find.btn_submit.click(function () {
|
||||
$app.on_send_find_password_email();
|
||||
});
|
||||
|
||||
$app.options.mode = 3;
|
||||
$app.dom.find.input_username.keydown(function (event) {
|
||||
if (event.which === 13) {
|
||||
$app.dom.find.input_email.focus();
|
||||
} else {
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
}
|
||||
});
|
||||
$app.dom.find.input_email.keydown(function (event) {
|
||||
if (event.which === 13) {
|
||||
$app.dom.find.input_captcha.focus();
|
||||
} else {
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
}
|
||||
});
|
||||
$app.dom.find.input_captcha.keydown(function (event) {
|
||||
if (event.which === 13) {
|
||||
$app.on_send_find_password_email();
|
||||
} else {
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
}
|
||||
});
|
||||
|
||||
$app.dom.set_password.btn_submit.click(function () {
|
||||
$app.on_set_new_password();
|
||||
});
|
||||
|
||||
$app.dom.set_password.input_password.keydown(function (event) {
|
||||
if (event.which === 13) {
|
||||
$app.on_set_new_password();
|
||||
} else {
|
||||
$('[data-toggle="popover"]').popover('hide');
|
||||
}
|
||||
});
|
||||
|
||||
$app.dom.set_password.btn_switch_password.click(function () {
|
||||
if ('password' === $app.dom.set_password.input_password.attr('type')) {
|
||||
$app.dom.set_password.input_password.attr('type', 'text');
|
||||
$app.dom.set_password.btn_switch_password_icon.removeClass('fa-eye').addClass('fa-eye-slash')
|
||||
} else {
|
||||
$app.dom.set_password.input_password.attr('type', 'password');
|
||||
$app.dom.set_password.btn_switch_password_icon.removeClass('fa-eye-slash').addClass('fa-eye')
|
||||
}
|
||||
});
|
||||
|
||||
if ($app.options.mode === 1) {
|
||||
// show 'find-my-password' page
|
||||
$app.dom.op_message = $app.dom.find.message;
|
||||
$app.dom.title.text('重置密码');
|
||||
$app.dom.icon_bg.addClass('fa fa-search-plus').css('color', '#4366de');
|
||||
$app.dom.captcha_image.attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
$app.dom.find_password_area.show();
|
||||
$app.dom.username.focus();
|
||||
$app.dom.icon_bg.addClass('fa fa-search-plus').css('color', '#286090');
|
||||
$app.dom.find.captcha_image.attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
$app.dom.find.area.show();
|
||||
$app.dom.find.input_username.focus();
|
||||
} else if ($app.options.mode === 2) {
|
||||
// show 'password-expired' page
|
||||
// show 'error' page
|
||||
$app.dom.icon_bg.addClass('fa fa-warning').css('color', '#ff6242');
|
||||
if ($app.options.code === TPE_NOT_EXISTS) {
|
||||
$app.dom.title.text('链接无效');
|
||||
$app.dom.err_message.html('当前使用的密码重置链接无效,可能已经因过期而被清除!密码重置链接仅在24小时内有效,请及时设置您的新密码!');
|
||||
$app.dom.error.message.html('当前使用的密码重置链接无效,可能已经因过期而被清除!密码重置链接仅在24小时内有效,请及时设置您的新密码!');
|
||||
} else if ($app.options.code === TPE_EXPIRED) {
|
||||
$app.dom.title.text('链接已过期');
|
||||
$app.dom.err_message.html('当前使用的密码重置链接已经过期!密码重置链接仅在24小时内有效,请及时设置您的新密码!');
|
||||
$app.dom.error.message.html('当前使用的密码重置链接已经过期!密码重置链接仅在24小时内有效,请及时设置您的新密码!');
|
||||
} else if ($app.options.code === TPE_NETWORK) {
|
||||
$app.dom.title.text('功能未启用');
|
||||
$app.dom.error.message.html('系统尚未配置邮件发送功能,无法进行密码找回操作!');
|
||||
} else if ($app.options.code === TPE_PRIVILEGE) {
|
||||
$app.dom.title.text('功能已禁用');
|
||||
$app.dom.error.message.html('根据系统配置,禁止进行密码找回操作!');
|
||||
} else {
|
||||
$app.dom.title.text('更新密码');
|
||||
$app.dom.title.text('发生错误!');
|
||||
$app.dom.error.message.html('很抱歉发生了错误:' + tp_error_msg($app.options.code));
|
||||
}
|
||||
$app.dom.err_area.show();
|
||||
$app.dom.error.area.show();
|
||||
} else if ($app.options.mode === 3) {
|
||||
// show 'set-new-password' page
|
||||
$app.dom.op_message = $app.dom.set_password.message;
|
||||
$app.dom.title.text('重置密码');
|
||||
$app.dom.icon_bg.addClass('fa fa-info-circle').css('color', '#357a3c');
|
||||
$app.dom.password_area.show();
|
||||
if ($app.options.force_strong)
|
||||
$app.dom.set_password.info.show();
|
||||
$app.dom.set_password.area.show();
|
||||
}
|
||||
|
||||
cb_stack.exec();
|
||||
};
|
||||
|
||||
$app.on_send_email = function() {
|
||||
|
||||
$app.hide_op_box = function () {
|
||||
$app.dom.op_message.hide();
|
||||
};
|
||||
|
||||
$app.show_op_box = function (op_type, op_msg) {
|
||||
$app.dom.op_message.html(op_msg);
|
||||
$app.dom.op_message.removeClass().addClass('op_box op_' + op_type);
|
||||
$app.dom.op_message.show();
|
||||
};
|
||||
|
||||
$app.on_send_find_password_email = function () {
|
||||
$app.hide_op_box();
|
||||
var str_username = $app.dom.find.input_username.val();
|
||||
var str_email = $app.dom.find.input_email.val();
|
||||
var str_captcha = $app.dom.find.input_captcha.val();
|
||||
|
||||
if (str_username.length === 0) {
|
||||
$app.show_op_box('error', '账号未填写!');
|
||||
$app.dom.find.input_username.attr('data-content', "请填写您的账号!").focus().popover('show');
|
||||
// $app.dom.find.input_username.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_email.length === 0) {
|
||||
$app.show_op_box('error', '邮箱未填写!');
|
||||
$app.dom.find.input_email.attr('data-content', "请填写您的邮箱!").focus().popover('show');
|
||||
// $app.dom.find.input_email.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_captcha.length !== 4) {
|
||||
$app.show_op_box('error', '验证码错误!');
|
||||
$app.dom.find.input_captcha.attr('data-content', "验证码为4位数字和字母的组合,请重新填写!").focus().select().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
$app.dom.find.btn_submit.attr('disabled', 'disabled');
|
||||
$tp.ajax_post_json('/auth/verify-captcha', {captcha: str_captcha},
|
||||
function (ret) {
|
||||
if (ret.code === TPE_OK) {
|
||||
// 验证成功
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('wait', '<i class="fa fa-circle-o-notch fa-spin"></i> 正在发送密码重置确认函,请稍候...');
|
||||
$app.do_send_reset_email(str_username, str_email, str_captcha);
|
||||
}
|
||||
else {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', tp_error_msg(ret.code, ret.message));
|
||||
$app.dom.captcha_image.attr('src', '/auth/captcha?h=28&rnd=' + Math.random());
|
||||
$app.dom.input_captcha.focus().select().val('');
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', '很抱歉,无法连接服务器!请稍后再试一次!');
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$app.do_send_reset_email = function (str_username, str_email, str_captcha) {
|
||||
$tp.ajax_post_json('/user/do-reset-password', {
|
||||
mode: 3,
|
||||
username: str_username,
|
||||
email: str_email,
|
||||
captcha: str_captcha
|
||||
},
|
||||
function (ret) {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
$app.show_op_box('success', '密码重置确认函已发送!');
|
||||
} else {
|
||||
$app.hide_op_box();
|
||||
var msg = '';
|
||||
if (ret.code === TPE_NOT_EXISTS)
|
||||
msg = tp_error_msg(ret.code, '没有此用户');
|
||||
else
|
||||
msg = tp_error_msg(ret.code, ret.message);
|
||||
$app.show_op_box('error', msg);
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', '网络故障,密码重置确认函发送失败!');
|
||||
},
|
||||
15000
|
||||
);
|
||||
};
|
||||
|
||||
$app.on_set_new_password = function () {
|
||||
$app.hide_op_box();
|
||||
var str_password = $app.dom.set_password.input_password.val();
|
||||
|
||||
if (str_password.length === 0) {
|
||||
$app.show_op_box('error', '密码未填写!');
|
||||
$app.dom.set_password.input_password.attr('data-content', "请设置您的新密码!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($app.options.force_strong) {
|
||||
if (!tp_check_strong_password(str_password)) {
|
||||
$app.show_op_box('error', '抱歉,不能使用弱密码!');
|
||||
$app.dom.set_password.input_password.attr('data-content', "请设置强密码:至少8位,必须包含大写字母、小写字母以及数字!").focus().popover('show');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$tp.ajax_post_json('/user/do-reset-password', {
|
||||
mode: 4,
|
||||
token: $app.options.token,
|
||||
password: str_password
|
||||
},
|
||||
function (ret) {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
if (ret.code === TPE_OK) {
|
||||
$app.show_op_box('success', '密码已重置,正在转到登录界面!');
|
||||
setTimeout(function () {
|
||||
window.location.href = '/';
|
||||
}, 2000);
|
||||
} else {
|
||||
var msg = '';
|
||||
if (ret.code === TPE_NOT_EXISTS)
|
||||
msg = tp_error_msg(ret.code, '无效的密码重置链接!');
|
||||
else
|
||||
msg = tp_error_msg(ret.code, ret.message);
|
||||
$app.show_op_box('error', msg);
|
||||
}
|
||||
},
|
||||
function () {
|
||||
$app.dom.find.btn_submit.removeAttr('disabled');
|
||||
$app.hide_op_box();
|
||||
$app.show_op_box('error', '网络故障,密码重置失败!');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -989,10 +989,8 @@ $app.create_dlg_reset_password = function () {
|
|||
dlg.do_send_reset_email = function () {
|
||||
dlg.dom.btn_send_reset_email.attr('disabled', 'disabled');
|
||||
$tp.ajax_post_json('/user/do-reset-password', {
|
||||
id: dlg.field_id,
|
||||
mode: 1,
|
||||
// email: dlg.field_email,
|
||||
password: ''
|
||||
id: dlg.field_id
|
||||
},
|
||||
function (ret) {
|
||||
dlg.dom.btn_send_reset_email.removeAttr('disabled');
|
||||
|
@ -1020,9 +1018,8 @@ $app.create_dlg_reset_password = function () {
|
|||
}
|
||||
|
||||
$tp.ajax_post_json('/user/do-reset-password', {
|
||||
id: dlg.field_id,
|
||||
mode: 2,
|
||||
// email: '',
|
||||
id: dlg.field_id,
|
||||
password: dlg.field_password
|
||||
},
|
||||
function (ret) {
|
||||
|
|
|
@ -40,13 +40,6 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
//@header-height: @top-navbar-height; // + @top-toolbar-height;
|
||||
|
||||
// 顶部状态栏
|
||||
//.page-header-fixed {
|
||||
//padding-top: @header-height;
|
||||
//}
|
||||
|
||||
.page-header {
|
||||
//border: none;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, .5);
|
||||
|
@ -166,6 +159,37 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.op_box {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
//border-radius: 3px;
|
||||
//text-align: center;
|
||||
//margin: 5px 20px 10px 20px;
|
||||
//margin: 5px 0;
|
||||
margin: 0;
|
||||
|
||||
&.op_error {
|
||||
//background: rgba(255, 5, 0, 0.5);
|
||||
background-color: #ffb8b5;
|
||||
border: 1px solid #d47e7b;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&.op_wait {
|
||||
//background: rgba(255, 255, 255, 0.3);
|
||||
background: #e5e5e5;
|
||||
border: 1px solid #a8a8a8;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&.op_success {
|
||||
//background: rgba(255, 255, 255, 0.3);
|
||||
background: #acf1b2;
|
||||
border: 1px solid #82df82;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
// for error/reset-password page
|
||||
.info-box {
|
||||
@error-icon-size: 164px;
|
||||
|
@ -203,11 +227,16 @@ body {
|
|||
hr {
|
||||
//border-top: 1px solid #d3d3d3;
|
||||
//border-bottom: 1px solid #fff;
|
||||
margin:10px 0 20px;
|
||||
margin: 10px 0 20px;
|
||||
border-top: none;
|
||||
border-bottom: 1px dashed #d3d3d3;
|
||||
}
|
||||
}
|
||||
|
||||
.op_box {
|
||||
margin: 5px 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// for maintenance page
|
||||
|
@ -293,25 +322,9 @@ body {
|
|||
}
|
||||
|
||||
.op_box {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
//text-align: center;
|
||||
//margin: 5px 20px 10px 20px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.op_error {
|
||||
//background: rgba(255, 5, 0, 0.5);
|
||||
background-color: #cc3632;
|
||||
border: 1px solid #9c2a26;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.op_wait {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.steps-detail {
|
||||
display: none;
|
||||
margin: 10px;
|
||||
|
|
|
@ -18,11 +18,14 @@
|
|||
<meta content="black-translucent" name="apple-mobile-web-app-status-bar-style">
|
||||
<title>${self.attr.page_title_[-1]}::TELEPORT</title>
|
||||
<link rel="shortcut icon" href="${ static_url('favicon.png') }">
|
||||
|
||||
<link href="${ static_url('plugins/bootstrap/css/bootstrap.min.css') }" rel="stylesheet" type="text/css"/>
|
||||
<link href="${ static_url('plugins/font-awesome/css/font-awesome.min.css') }" rel="stylesheet">
|
||||
<link href="${ static_url('plugins/gritter/css/jquery.gritter.css') }" rel="stylesheet">
|
||||
<link href="${ static_url('plugins/jquery/jquery.mCustomScrollbar.min.css') }" rel="stylesheet">
|
||||
|
||||
<link href="${ static_url('css/style.css') }" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<%block name="extend_css_file"/>
|
||||
<%block name="embed_css"/>
|
||||
</head>
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
<link href="${ static_url('plugins/bootstrap/css/bootstrap.min.css') }" rel="stylesheet" type="text/css"/>
|
||||
<link href="${ static_url('plugins/font-awesome/css/font-awesome.min.css') }" rel="stylesheet">
|
||||
|
||||
## <link href="${ static_url('css/error.css') }" rel="stylesheet" type="text/css"/>
|
||||
<link href="${ static_url('plugins/gritter/css/jquery.gritter.css') }" rel="stylesheet">
|
||||
|
||||
<link href="${ static_url('css/single.css') }" rel="stylesheet" type="text/css"/>
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<style type="text/css">
|
||||
.input-addon-desc {
|
||||
text-align: right;
|
||||
font-size: 80%;
|
||||
font-size: 90%;
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
|
@ -43,38 +43,42 @@
|
|||
<hr/>
|
||||
<div id="content" class="content">
|
||||
|
||||
<div id="error-area" style="display:none;">
|
||||
<div id="err-message" class="alert alert-danger"></div>
|
||||
<div id="err-actions">
|
||||
现在您可以:
|
||||
<div id="area-error" style="display:none;">
|
||||
<div data-field="message" class="alert alert-danger"></div>
|
||||
<div>
|
||||
您可以:
|
||||
<ul>
|
||||
<li><a href="/user/reset-password">尝试重新找回密码</a></li>
|
||||
<li>联系管理员手工重置密码</li>
|
||||
<li><a href="/user/reset-password">稍后再尝试重置密码</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="find-my-password" style="display: none;">
|
||||
<div id="area-find-password" style="display: none;">
|
||||
<div class="row" style="padding:0 20px;">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-user-circle-o fa-fw"></i></span>
|
||||
<input id="username" type="text" class="form-control mono" placeholder="teleport系统用户名">
|
||||
<input data-field="input-username" type="text" class="form-control mono" placeholder="teleport系统用户名" data-toggle="popover" data-trigger="manual" data-placement="top">
|
||||
</div>
|
||||
<div class="input-group" style="margin-top:10px;">
|
||||
<span class="input-group-addon"><i class="fa fa-envelope-o fa-fw"></i></span>
|
||||
<input id="email" type="text" class="form-control mono" placeholder="用户绑定的电子邮箱">
|
||||
<input data-field="input-email" type="text" class="form-control mono" placeholder="用户绑定的电子邮箱" data-toggle="popover" data-trigger="manual" data-placement="top">
|
||||
</div>
|
||||
|
||||
<div class="input-group" style="margin-top:10px;">
|
||||
<span class="input-group-addon"><i class="fa fa-check-square-o fa-fw"></i></span>
|
||||
<input id="captcha" type="text" class="form-control" placeholder="验证码"
|
||||
data-toggle="popover" data-trigger="manual" data-placement="top">
|
||||
<span class="input-group-addon captcha-box"><a href="javascript:;"><img id="captcha-image" src=""></a></span>
|
||||
<input data-field="input-captcha" type="text" class="form-control" placeholder="验证码" data-toggle="popover" data-trigger="manual" data-placement="top">
|
||||
<span class="input-group-addon captcha-box"><a href="javascript:;"><img data-field="captcha-image" src=""></a></span>
|
||||
</div>
|
||||
<p class="input-addon-desc">验证码,点击图片可更换</p>
|
||||
|
||||
<div style="margin:20px 0;">
|
||||
<button type="button" class="btn btn-primary" data-field="btn-submit" style="width:100%;"><i class="fa fa-send fa-fw"></i> 发送密码重置确认函</button>
|
||||
<div data-field="message" class="alert alert-danger" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-7">
|
||||
<div class="alert alert-info">
|
||||
<p>请填写用户信息,随后一封密码重置确认函将发送到您的邮箱。</p>
|
||||
<p>请注意,密码重置确认函在24小时内有效!</p>
|
||||
|
@ -83,43 +87,29 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="padding:0 20px;margin-top:10px;">
|
||||
<div class="col-md-4">
|
||||
<button type="button" class="btn btn-primary" id="btn-send-email" style="width:100%;"><i class="fa fa-send fa-fw"></i> 发送密码重置确认函</button>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div id="send-result" class="alert alert-danger" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="password-area" style="display:none;">
|
||||
<div class="row" style="padding:0 20px;">
|
||||
<div class="col-md-4">
|
||||
<div id="area-set-password" style="display:none;">
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-edit"></i></span>
|
||||
<input data-field="password" type="password" class="form-control mono" placeholder="设置新密码">
|
||||
<span class="input-group-btn"><button class="btn btn-default" type="button" id="btn-switch-password"><i class="fa fa-eye fa-fw"></i></button></span>
|
||||
<input data-field="input-password" type="password" class="form-control mono" placeholder="设置新密码" data-toggle="popover" data-trigger="manual" data-placement="top">
|
||||
<span class="input-group-btn"><button class="btn btn-default" type="button" data-field="btn-switch-password"><i class="fa fa-eye fa-fw"></i></button></span>
|
||||
</div>
|
||||
|
||||
<div style="margin:20px 0;">
|
||||
<button type="button" class="btn btn-primary" data-field="btn-submit" style="width:100%;"><i class="fa fa-check fa-fw"></i> 重置密码</button>
|
||||
<div data-field="message" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="alert alert-warning">
|
||||
<div class="col-md-7">
|
||||
<div data-field="info" class="alert alert-warning" style="display:none;">
|
||||
<p>注意,系统启用强密码策略,要求密码至少8位,必须包含大写字母、小写字母以及数字。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="padding:0 20px;margin-top:10px;">
|
||||
<div class="col-md-4">
|
||||
<button type="button" class="btn btn-primary" id="btn-reset-password" style="width:100%;"><i class="fa fa-check fa-fw"></i> 重置密码</button>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div id="reset-result" class="alert alert-danger" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -460,11 +460,10 @@ class AppConfig(BaseAppConfig):
|
|||
# =====================================
|
||||
# 密码策略相关
|
||||
# =====================================
|
||||
# conf_data['password'] = '{"find":false,"strong":true}'
|
||||
try:
|
||||
_password = json.loads(conf_data['password'])
|
||||
except:
|
||||
log.w('invalid password config, use default.\n')
|
||||
log.w('password config not set or invalid, use default.\n')
|
||||
_password = {}
|
||||
|
||||
self.sys.password = tp_convert_to_attr_dict(_password)
|
||||
|
@ -481,7 +480,7 @@ class AppConfig(BaseAppConfig):
|
|||
try:
|
||||
_login = json.loads(conf_data['login'])
|
||||
except:
|
||||
log.w('invalid login config, use default.\n')
|
||||
log.w('login config not set or invalid, use default.\n')
|
||||
_login = {}
|
||||
|
||||
self.sys.login = tp_convert_to_attr_dict(_login)
|
||||
|
@ -493,7 +492,6 @@ class AppConfig(BaseAppConfig):
|
|||
self.sys.login.lock_timeout = 30 # 30 min
|
||||
if not self.sys.login.is_exists('auth'):
|
||||
self.sys.login.auth = TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA | TP_LOGIN_AUTH_USERNAME_OATH | TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH
|
||||
# print('==login==', json.dumps(self.sys.login, separators=(',', ':')))
|
||||
|
||||
# =====================================
|
||||
# SMTP相关
|
||||
|
@ -502,7 +500,7 @@ class AppConfig(BaseAppConfig):
|
|||
try:
|
||||
_smtp = json.loads(conf_data['smtp'])
|
||||
except:
|
||||
log.w('invalid smtp config, use default.\n')
|
||||
log.w('smtp config not set or invalid, use default.\n')
|
||||
_smtp = {}
|
||||
|
||||
self.sys.smtp = tp_convert_to_attr_dict(_smtp)
|
||||
|
@ -517,7 +515,6 @@ class AppConfig(BaseAppConfig):
|
|||
if self.sys.smtp.is_exists('password'):
|
||||
self.sys_smtp_password = self.sys.smtp.password
|
||||
self.sys.smtp.password = '********'
|
||||
# del self.sys.smtp.password
|
||||
|
||||
# =====================================
|
||||
# 存储相关
|
||||
|
@ -525,7 +522,7 @@ class AppConfig(BaseAppConfig):
|
|||
try:
|
||||
_storage = json.loads(conf_data['storage'])
|
||||
except:
|
||||
log.w('invalid storage config, use default.\n')
|
||||
log.w('storage config not set or invalid, use default.\n')
|
||||
_storage = {}
|
||||
|
||||
self.sys.storage = tp_convert_to_attr_dict(_storage)
|
||||
|
|
|
@ -104,6 +104,10 @@ class DoLoginHandler(TPBaseJsonHandler):
|
|||
syslog.sys_log({'username': username, 'surname': username}, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,用户`{}`不存在'.format(username))
|
||||
return self.write_json(err)
|
||||
|
||||
if user_info.privilege == 0:
|
||||
# 尚未为此用户设置角色
|
||||
return self.write_json(TPE_PRIVILEGE, '用户尚未分配角色')
|
||||
|
||||
if user_info['state'] == TP_STATE_LOCKED:
|
||||
# 用户已经被锁定,如果系统配置为一定时间后自动解锁,则更新一下用户信息
|
||||
if sys_cfg.login.lock_timeout != 0:
|
||||
|
|
|
@ -85,9 +85,17 @@ class ResetPasswordHandler(TPBaseHandler):
|
|||
|
||||
_token = self.get_argument('token', None)
|
||||
if _token is None:
|
||||
param['mode'] = 1 # mode=1, show 'find-my-password' page.
|
||||
# 如果尚未设置SMTP或者系统限制,不允许发送密码重置邮件
|
||||
if len(get_cfg().sys.smtp.server) == 0:
|
||||
param['mode'] = 2 # mode=2, show 'error' page
|
||||
param['code'] = TPE_NETWORK
|
||||
elif not get_cfg().sys.password.allow_reset:
|
||||
param['mode'] = 2 # mode=2, show 'error' page
|
||||
param['code'] = TPE_PRIVILEGE
|
||||
else:
|
||||
param['mode'] = 1 # mode=1, show 'find-my-password' page.
|
||||
else:
|
||||
err = user.check_reset_token(_token)
|
||||
err, _ = user.check_reset_token(_token)
|
||||
|
||||
param['code'] = err
|
||||
param['token'] = _token
|
||||
|
@ -96,6 +104,7 @@ class ResetPasswordHandler(TPBaseHandler):
|
|||
param['mode'] = 2 # mode=2, show 'error' page
|
||||
else:
|
||||
param['mode'] = 3 # mode=3, show 'set-new-password' page
|
||||
param['force_strong'] = get_cfg().sys.password.force_strong
|
||||
|
||||
self.render('user/reset-password.mako', page_param=json.dumps(param))
|
||||
|
||||
|
@ -457,9 +466,6 @@ class DoSetRoleForUsersHandler(TPBaseJsonHandler):
|
|||
class DoResetPasswordHandler(TPBaseJsonHandler):
|
||||
@tornado.gen.coroutine
|
||||
def post(self):
|
||||
ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE)
|
||||
if ret != TPE_OK:
|
||||
return
|
||||
|
||||
args = self.get_argument('args', None)
|
||||
if args is None:
|
||||
|
@ -470,23 +476,80 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
|
|||
return self.write_json(TPE_JSON_FORMAT)
|
||||
|
||||
try:
|
||||
user_id = int(args['id'])
|
||||
mode = int(args['mode'])
|
||||
password = args['password']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
password = ''
|
||||
|
||||
if mode == 1:
|
||||
# 管理员直接在后台给用户发送密码重置邮件
|
||||
err = self.check_privilege(TP_PRIVILEGE_USER_CREATE)
|
||||
if err != TPE_OK:
|
||||
return self.write_json(err)
|
||||
|
||||
try:
|
||||
user_id = int(args['id'])
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
elif mode == 2:
|
||||
# 管理员直接在后台为用户重置密码
|
||||
err = self.check_privilege(TP_PRIVILEGE_USER_CREATE)
|
||||
if err != TPE_OK:
|
||||
return self.write_json(err)
|
||||
|
||||
try:
|
||||
user_id = int(args['id'])
|
||||
password = args['password']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
elif mode == 3:
|
||||
# 用户自行找回密码,需要填写用户名、邮箱、验证码
|
||||
try:
|
||||
username = args['username']
|
||||
email = args['email']
|
||||
captcha = args['captcha']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
code = self.get_session('captcha')
|
||||
if code is None:
|
||||
return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效')
|
||||
if code.lower() != captcha.lower():
|
||||
return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误')
|
||||
|
||||
self.del_session('captcha')
|
||||
err, user_info = user.get_by_username(username)
|
||||
if err != TPE_OK:
|
||||
return self.write_json(err)
|
||||
if user_info.email != email:
|
||||
return self.write_json(TPE_NOT_EXISTS)
|
||||
|
||||
user_id = user_info.id
|
||||
|
||||
elif mode == 4:
|
||||
# 用户通过密码重置邮件中的链接(有token验证),在页面上设置新密码,需要提供token、新密码
|
||||
try:
|
||||
token = args['token']
|
||||
password = args['password']
|
||||
except:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
err, user_id = user.check_reset_token(token)
|
||||
if err != TPE_OK:
|
||||
return self.write_json(err)
|
||||
|
||||
else:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
if user_id == 0:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
if mode == 1:
|
||||
# if len(email) == 0:
|
||||
# return self.write_json(TPE_PARAM)
|
||||
|
||||
if mode == 1 or mode == 3:
|
||||
err, email, token = user.generate_reset_password_token(self, user_id)
|
||||
|
||||
print(err, email, token)
|
||||
|
||||
# 生成一个密码重置链接,24小时有效
|
||||
# token = tp_generate_random(16)
|
||||
reset_url = '{}://{}/user/reset-password?token={}'.format(self.request.protocol, self.request.host, token)
|
||||
|
@ -494,17 +557,19 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
|
|||
|
||||
err, msg = yield mail.tp_send_mail(
|
||||
email,
|
||||
'您好!\n\n请访问以下链接以重设您的TELEPORT登录密码。此链接将于本邮件寄出24小时之后失效。访问此链接,将会为您打开密码重置页面,然后您可以设定新密码。\n\n'
|
||||
'如果您并没有做重设密码的操作,请及时联系系统管理员!\n\n'
|
||||
'{reset_url}\n\n'
|
||||
'Teleport用户,您好!\n\n请访问以下链接以重设您的teleport登录密码。此链接将于本邮件寄出24小时之后失效。\n'
|
||||
'访问此链接,将会为您打开密码重置页面,然后您可以设定新密码。\n\n'
|
||||
'如果您并没有做重设密码的操作,请忽略本邮件,请及时联系您的系统管理员!\n\n'
|
||||
'{reset_url}\n\n\n\n'
|
||||
'[本邮件由teleport系统自动发出,请勿回复]'
|
||||
'\n\n'
|
||||
''.format(reset_url=reset_url),
|
||||
subject='密码重置邮件'
|
||||
subject='密码重置确认函'
|
||||
)
|
||||
|
||||
return self.write_json(err, msg)
|
||||
|
||||
elif mode == 2:
|
||||
elif mode == 2 or mode == 4:
|
||||
if len(password) == 0:
|
||||
return self.write_json(TPE_PARAM)
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ def get_by_username(username):
|
|||
if len(s.recorder) == 0:
|
||||
return TPE_NOT_EXISTS, {}
|
||||
|
||||
if s.recorder[0]['privilege'] is None:
|
||||
s.recorder[0]['privilege'] = 0
|
||||
|
||||
return TPE_OK, s.recorder[0]
|
||||
|
||||
|
||||
|
@ -300,13 +303,13 @@ def check_reset_token(token):
|
|||
db.query(sql, (_time_now - 3 * 24 * 60 * 60,))
|
||||
|
||||
# 1. query user's id
|
||||
sql = 'SELECT create_time FROM `{dbtp}user_rpt` WHERE token={dbph};'.format(dbtp=db.table_prefix, dbph=db.place_holder)
|
||||
sql = 'SELECT user_id, create_time FROM `{dbtp}user_rpt` WHERE token={dbph};'.format(dbtp=db.table_prefix, dbph=db.place_holder)
|
||||
db_ret = db.query(sql, (token,))
|
||||
if db_ret is None or len(db_ret) == 0:
|
||||
return TPE_NOT_EXISTS
|
||||
return TPE_NOT_EXISTS, 0
|
||||
|
||||
# user_id = db_ret[0][0]
|
||||
create_time = db_ret[0][0]
|
||||
user_id = db_ret[0][0]
|
||||
create_time = db_ret[0][1]
|
||||
|
||||
# err = s.select_from('user', ['email'], alt_name='u').where('u.id="{user_id}"'.format(user_id=user_id)).query()
|
||||
# if err != TPE_OK:
|
||||
|
@ -316,9 +319,9 @@ def check_reset_token(token):
|
|||
# email = s.recorder[0].email
|
||||
|
||||
if _time_now - create_time > 24 * 60 * 60:
|
||||
return TPE_EXPIRED
|
||||
return TPE_EXPIRED, user_id
|
||||
else:
|
||||
return TPE_OK
|
||||
return TPE_OK, user_id
|
||||
|
||||
|
||||
def update_login_info(handler, user_id):
|
||||
|
|
Loading…
Reference in New Issue