pull/105/head
ApexLiu 2017-11-13 08:23:19 +08:00
parent d634995bba
commit 7e1f6705e7
9 changed files with 177 additions and 22 deletions

View File

@ -191,6 +191,7 @@ var TPE_NOT_EXISTS = 9;
var TPE_FAILED = 100; // 内部错误
var TPE_NETWORK = 101; // 网络错误
var TPE_DATABASE = 102; // 数据库操作失败
var TPE_EXPIRED = 103; // 数据/操作等已过期
// HTTP请求相关错误
var TPE_HTTP_METHOD = 120; // 无效的请求方法不是GET/POST等或者错误的请求方法例如需要POST却使用GET方式请求

View File

@ -988,7 +988,7 @@ $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/reset-password', {
$tp.ajax_post_json('/user/do-reset-password', {
id: dlg.field_id,
mode: 1,
// email: dlg.field_email,
@ -1019,7 +1019,7 @@ $app.create_dlg_reset_password = function () {
return;
}
$tp.ajax_post_json('/user/reset-password', {
$tp.ajax_post_json('/user/do-reset-password', {
id: dlg.field_id,
mode: 2,
// email: '',

View File

@ -0,0 +1,108 @@
<%!
page_title_ = '设置密码'
# page_menu_ = ['error']
%>
<%inherit file="../page_single_base.mako"/>
<%block name="header_title">
<a href="http://teleport.eomsoft.net" target="_blank"><span class="logo"></span></a>
</%block>
<%block name="extend_css_file">
<link href="${ static_url('css/error.css') }" rel="stylesheet" type="text/css"/>
</%block>
<div class="page-content">
<div class="error-box">
<div class="error-icon-box">
<i class="fa fa-warning"></i>
</div>
<div class="error-message-box">
<div id="title" class="title">设置密码</div>
<hr/>
<div id="content" class="content">
<div id="error-area" style="display:none;">
<div id="message" class="alert alert-danger"></div>
<div id="actions" style="display: none;">
您可以:
<ul>
<li>重新找回密码</li>
<li>联系管理员重置密码</li>
</ul>
</div>
</div>
<div id="find-my-password" style="display: none;">
find-my-password
</div>
<div id="password-area" style="display:none;">
<div id="policy" class="alert alert-warning" style="margin-top:10px;">
注意为增强系统安全系统启用强密码策略要求密码至少8位必须包含大写字母、小写字母以及数字。
</div>
<div class="form-group form-group-sm">
<div class="col-sm-4">
<div class="input-group">
<input data-field="password" type="password" class="form-control mono" placeholder="设置新密码">
<span class="input-group-btn"><button class="btn btn-sm btn-default" type="button" id="btn-switch-password"><i class="fa fa-eye fa-fw"></i></button></span>
</div>
</div>
<div class="col-sm-8">
<button type="button" class="btn btn-sm btn-primary" id="btn-reset-password"><i class="fa fa-check fa-fw"></i> 重置密码</button>
</div>
</div>
<div class="clear-float"></div>
</div>
</div>
</div>
</div>
</div>
<%block name="embed_js">
<script type="text/javascript">
"use strict";
$app.add_options(${page_param});
console.log($app.options);
$app.dom = {
title: $('#title'),
err_area: $('#error-area'),
message: $('#message'),
actions: $('#actions'),
find_password_area: $('#find-my-password'),
password_area: $('#password-area')
};
if($app.options.mode === 1) {
// show 'find-my-password' page
$app.dom.title.text('找回密码');
$app.dom.find_password_area.show();
} else if($app.options.mode === 2) {
// show 'password-expired' page
$app.dom.title.text('更新密码');
} else if($app.options.mode === 3) {
// show 'set-new-password' page
$app.dom.title.text('重置密码');
$app.dom.password_area.show();
}
## if($app.options.code !== TPE_OK) {
## $app.dom.message.addClass('alert alert-danger');
##
## if($app.options.code === TPE_EXPIRED)
## $app.dom.message.html('很抱歉,此密码重置链接已过期!');
## else if($app.options.code === TPE_NOT_EXISTS)
## $app.dom.message.html('很抱歉,此密码重置链接是无效的!');
##
## $app.dom.err_area.show();
## $app.dom.actions.show();
## } else {
## $app.dom.password_area.show();
## }
</script>
</%block>

View File

@ -191,10 +191,10 @@ class TPDatabase:
log.e('Unknown database type.\n')
return None
def query(self, sql):
log.d('[db] {}\n'.format(sql))
def query(self, sql, args=()):
log.d('[db] {}, {}\n'.format(sql, args))
# _start = datetime.datetime.utcnow().timestamp()
ret = self._conn_pool.query(sql)
ret = self._conn_pool.query(sql, args)
# _end = datetime.datetime.utcnow().timestamp()
# log.d('[db] cost {} seconds.\n'.format(_end - _start))
return ret
@ -325,11 +325,11 @@ class TPDatabasePool:
self._locker = threading.RLock()
self._connections = dict()
def query(self, sql):
def query(self, sql, args):
_conn = self._get_connect()
if _conn is None:
return None
return self._do_query(_conn, sql)
return self._do_query(_conn, sql, args)
def exec(self, sql, args):
_conn = self._get_connect()
@ -364,7 +364,7 @@ class TPDatabasePool:
def _do_connect(self):
return None
def _do_query(self, conn, sql):
def _do_query(self, conn, sql, args):
return None
def _do_exec(self, conn, sql, args):
@ -393,10 +393,10 @@ class TPSqlitePool(TPDatabasePool):
log.e('[sqlite] can not connect, does the database file correct?\n')
return None
def _do_query(self, conn, sql):
def _do_query(self, conn, sql, args):
cursor = conn.cursor()
try:
cursor.execute(sql)
cursor.execute(sql, args)
db_ret = cursor.fetchall()
return db_ret
except Exception as e:
@ -467,11 +467,11 @@ class TPMysqlPool(TPDatabasePool):
log.e('[mysql] connect [{}:{}] failed: {}\n'.format(self._host, self._port, e.__str__()))
return None
def _do_query(self, conn, sql):
def _do_query(self, conn, sql, args):
for retry in range(2):
cursor = conn.cursor()
try:
cursor.execute(sql)
cursor.execute(sql, args)
db_ret = cursor.fetchall()
conn.commit()
return db_ret
@ -501,11 +501,11 @@ class TPMysqlPool(TPDatabasePool):
finally:
cursor.close()
def _do_exec(self, conn, sql):
def _do_exec(self, conn, sql, args):
for retry in range(2):
cursor = conn.cursor()
try:
cursor.execute(sql)
cursor.execute(sql, args)
conn.commit()
return True
except pymysql.err.OperationalError as e:

View File

@ -173,6 +173,7 @@ TPE_NOT_EXISTS = 9
TPE_FAILED = 100
TPE_NETWORK = 101
TPE_DATABASE = 102
TPE_EXPIRED = 103
TPE_HTTP_METHOD = 120
TPE_HTTP_URL_ENCODE = 121

View File

@ -55,8 +55,6 @@ controllers = [
# (r'/auth/oath-secret-qrcode', auth.OathSecretQrCodeHandler),
# (r'/auth/oath-secret-reset', auth.OathSecretResetHandler),
# (r'/auth/oath-update-secret', auth.OathUpdateSecretHandler),
# - 用户重设密码页面 /auth/reset-password?token=D3672DFF256B6B6F37AF8A922D7D83B4
(r'/auth/reset-password?token=D3672DFF256B6B6F37AF8A922D7D83B4', auth.ResetPasswordByTokenHandler),
#
# # (r"/log/replay/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(cfg.data_path, 'replay')}),
# (r"/log/replay/(.*)", record.ReplayStaticFileHandler, {"path": os.path.join(get_cfg().data_path, 'replay')}),
@ -86,7 +84,9 @@ controllers = [
# - [json] 获取用户列表
(r'/user/get-users', user.DoGetUsersHandler),
# - [json] 重置密码
(r'/user/reset-password', user.DoResetPasswordHandler),
(r'/user/do-reset-password', user.DoResetPasswordHandler),
# - 用户重设密码页面 /auth/reset-password?token=D3672DFF256B6B6F37AF8A922D7D83B4
(r'/user/reset-password', user.ResetPasswordHandler),
# - 用户组管理页面
(r'/user/group', user.GroupListHandler),

View File

@ -204,10 +204,6 @@ class VerifyCaptchaHandler(TPBaseJsonHandler):
return self.write_json(TPE_OK)
class ResetPasswordByTokenHandler(TPBaseHandler):
def get(self):
pass
# class ModifyPwd(TPBaseUserAuthJsonHandler):
# def post(self):
# args = self.get_argument('args', None)

View File

@ -75,6 +75,28 @@ class MeHandler(TPBaseHandler):
self.render('user/me.mako')
class ResetPasswordHandler(TPBaseHandler):
def get(self):
param = {
'mode': 0, # mode=1, unknown mode.
'token': '',
'code': TPE_PARAM
}
_mode = self.get_argument('mode', 1)
_token = self.get_argument('token', None)
if _token is None:
param['mode'] = 1 # mode=1, show 'find-my-password' page.
else:
err, email = user.check_reset_token(_token)
param['mode'] = 3 # mode=3, show 'set-new-password' page
param['token'] = _token
param['email'] = email
param['code'] = err
self.render('user/reset-password.mako', page_param=json.dumps(param))
class DoGetUserInfoHandler(TPBaseJsonHandler):
def post(self, user_id):
ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE | TP_PRIVILEGE_USER_DELETE | TP_PRIVILEGE_USER_LOCK | TP_PRIVILEGE_USER_GROUP)
@ -465,7 +487,7 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
# 生成一个密码重置链接24小时有效
# token = tp_generate_random(16)
reset_url = '{}://{}/user/validate-password-reset-token?token={}'.format(self.request.protocol, self.request.host, token)
reset_url = '{}://{}/user/reset-password?token={}'.format(self.request.protocol, self.request.host, token)
# reset_url = 'http://127.0.0.1/user/validate-password-reset-token?token=G66LXH0EOJ47OXTH7O5KBQ0PHXRSBXBVVFALI6JBJ8HNWUALWI35QECPJ8UV8DEQ'
err, msg = yield mail.tp_send_mail(

View File

@ -290,6 +290,33 @@ def generate_reset_password_token(handler, user_id):
return TPE_OK, email, token
def check_reset_token(token):
db = get_db()
s = SQL(db)
_time_now = tp_timestamp_utc_now()
# 0. query user's id
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, ''
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:
return err, ''
if len(s.recorder) == 0:
return TPE_DATABASE, ''
email = s.recorder[0].email
if _time_now - create_time > 24 * 60 * 60:
return TPE_EXPIRED, email
else:
return TPE_OK, email
def update_login_info(handler, user_id):
db = get_db()
_time_now = tp_timestamp_utc_now()