temp.
							parent
							
								
									d634995bba
								
							
						
					
					
						commit
						7e1f6705e7
					
				| 
						 | 
				
			
			@ -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方式请求)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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: '',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue