def api_failure_incr(): current = redis_store.exists("api_failure") redis_store.incr("api_failure", amount=1) if not current: now = datetime.now() expire = now.replace(minute=(now.minute + (now.minute % 15)), second=0, microsecond=0) redis_store.expireat("api_failure", expire)
def api_daily_incr(): current = redis_store.exists("api_daily") redis_store.incr("api_daily", amount=1) if not current: now = datetime.now() expire = now.replace(day=(now.day + 1), hour=0, minute=0, second=0, microsecond=0) redis_store.expireat("api_daily", expire)
def persist_notification(template_id, template_version, recipient, service_id, personalisation, notification_type, api_key_id, key_type, created_at=None, job_id=None, job_row_number=None, reference=None, notification_id=None): notification = Notification( id=notification_id, template_id=template_id, template_version=template_version, to=recipient, service_id=service_id, personalisation=personalisation, notification_type=notification_type, api_key_id=api_key_id, key_type=key_type, created_at=created_at or datetime.utcnow(), job_id=job_id, job_row_number=job_row_number, client_reference=reference ) dao_create_notification(notification) redis_store.incr(redis.daily_limit_cache_key(service_id)) return notification
def getIncEntityID(eventName): ID = redis_store.get(eventName + '.entityID') if ID is None: redis_store.set(eventName + '.entityID', 1) ID = 1 redis_store.incr(eventName + '.entityID') return int(ID)
def wrapped(*args, **kw): # 存入redis的key key = ":".join(["ratelimit", by()]) # 获取单位时间内剩余的请求次数 try: remaining = requests - int(redis_store.get(key)) except (ValueError, TypeError): remaining = requests redis_store.set(key, 0) # 获取剩余单位时间周期的时间(秒) ttl = redis_store.ttl(key) if ttl < 0: # 已过期,则设置过期时间(ttl = -2, ttl = -1) redis_store.expire(key, window) ttl = window # 将rate limites情况写入g g.view_limits = (requests, remaining - 1, time.time() + ttl) if remaining > 0: # 剩余请求次数>0,则redis记录+1,并进入后续处理 redis_store.incr(key, 1) # 未达到限制次数,记录到g,方便dispatch处理 g.status_code = 200 return func(*args, **kw) else: # return make_response('Too Many Requests', 429) # 这里无法直接返回429,而是记录到g.status_code, 方便dispatch处理 g.status_code = 429 return func(*args, **kw)
def post(self): """ 用户认证 :return: """ # 获取前端传参 req_data = request.get_json() username = req_data.get("username") password = req_data.get("password") # 判断数据是否为空 if not all([username, password]): return jsonify(code=RET.NODATA, codemsg="Username or Passowrd is None.") try: # 按用户查找数据是否存在 User_Data = Users_Models.query.filter_by(username=username).first() token = Users_Models.generate_auth_token(User_Data) except (IntegrityError, AttributeError) as e: current_app.logger.error(e) return jsonify(code=RET.NODATA, codemsg="User Data No Exist.") except Exception as e: current_app.logger.error(e) return jsonify(code=RET.DBERR, codemsg="Database Error.") try: # 从redis获取用户错误次数 Access_Nums = redis_store.get("access_login_error_number_%s" % username) except Exception as e: current_app.logger.error(e) else: # 判断redis访问错误是否为空或是否大于限制。 if Access_Nums is not None and int( Access_Nums) >= LOGIN_ERROR_MAX_TIMES: return jsonify(code=RET.REQERR, codemsg="Login errors are excessive.") # 判断用户是否存在或密码是否正确。 if User_Data is None or not User_Data.check_password(password): try: # 如果检测失败则保存信息到redis中,expire设置错误信息有效期 redis_store.incr("access_login_error_number_%s" % username) redis_store.expire("access_login_error_number_%s" % username, LOGIN_ERROR_FORBID_TIME) except Exception as e: current_app.logger.error(e) return jsonify(code=RET.DATAERR, codemsg="User or Password Auth Error.") return jsonify(code=RET.OK, codemsg="Succeed.", token=token)
def login(): try: ip_addr = request.headers['X-real-ip'] except: ip_addr = request.remote_addr form = LoginForm() if form.validate_on_submit(): form_data = form.data user = form.get_user() if user is None: flash('用户不存在') return redirect(url_for('auth.login')) if user.status == 0: flash('该账户已经被限制登录') return redirect(url_for('auth.login')) if not user.check_password(form_data['password']): flash('密码错误,请重试!') redis_store.incr('{}'.format(ip_addr), 1) redis_store.expire('{}'.format(ip_addr), 3600) return redirect(url_for('auth.login')) if 'code_text' in session and form_data['validate'].lower( ) != session['code_text'].lower(): flash(u'验证码错误!') return redirect(url_for('auth.login')) login_user(user, remember=form.remember_me.data) user.last_login = datetime.datetime.now() redis_store.delete('{}'.format(ip_addr)) url = requests.get('http://ip.taobao.com/service/getIpInfo.php?ip=%s' % ip_addr) data = url.json() user.ip_addr = ip_addr user.country = data['data']['country'] user.area = data['data']['area'] user.region = data['data']['region'] user.city = data['data']['city'] user.county = data['data']['county'] flash('欢迎回来,%s' % user.username) next_url = request.args.get('next') return redirect(next_url or url_for('public.index')) n_ip = redis_store.get('{}'.format(ip_addr)) pass_error_count = int(n_ip) if n_ip else None if not pass_error_count: try: session.pop('code_text') except: pass return render_template('auth/login.html', title='用户登录', form=form, pass_error_count=pass_error_count)
def check_token(): ''' 验证token, 如果同一IP认证失败5次,则封禁5分钟 ''' client_ip = request.remote_addr deny_num = redis_store.get(client_ip) deny_num = int(deny_num) if deny_num else 0 if deny_num >= 5: return unauthorized() TOKEN = current_app.config.get('TOKEN') try: key = request.headers.get('token') except: return bad_request() if not key or TOKEN != key: redis_store.incr(client_ip) redis_store.expire(client_ip, 60*5) return forbidden()
def persist_notification(*, template_id, template_version, recipient=None, service, personalisation, notification_type, api_key_id, key_type, created_at=None, job_id=None, job_row_number=None, reference=None, client_reference=None, notification_id=None, simulated=False, created_by_id=None, status=NOTIFICATION_CREATED, reply_to_text=None, billable_units=None, postage=None, template_postage=None, recipient_identifier=None): notification_created_at = created_at or datetime.utcnow() if not notification_id: notification_id = uuid.uuid4() notification = Notification(id=notification_id, template_id=template_id, template_version=template_version, to=recipient, service_id=service.id, service=service, personalisation=personalisation, notification_type=notification_type, api_key_id=api_key_id, key_type=key_type, created_at=notification_created_at, job_id=job_id, job_row_number=job_row_number, client_reference=client_reference, reference=reference, created_by_id=created_by_id, status=status, reply_to_text=reply_to_text, billable_units=billable_units) if accept_recipient_identifiers_enabled() and recipient_identifier: _recipient_identifier = RecipientIdentifier( notification_id=notification_id, id_type=recipient_identifier['id_type'], id_value=recipient_identifier['id_value']) notification.recipient_identifiers.set(_recipient_identifier) if notification_type == SMS_TYPE and notification.to: formatted_recipient = validate_and_format_phone_number( recipient, international=True) recipient_info = get_international_phone_info(formatted_recipient) notification.normalised_to = formatted_recipient notification.international = recipient_info.international notification.phone_prefix = recipient_info.country_prefix notification.rate_multiplier = recipient_info.billable_units elif notification_type == EMAIL_TYPE and notification.to: notification.normalised_to = format_email_address(notification.to) elif notification_type == LETTER_TYPE: notification.postage = postage or template_postage # if simulated create a Notification model to return but do not persist the Notification to the dB if not simulated: dao_create_notification(notification) if key_type != KEY_TYPE_TEST: if redis_store.get(redis.daily_limit_cache_key(service.id)): redis_store.incr(redis.daily_limit_cache_key(service.id)) current_app.logger.info("{} {} created at {}".format( notification_type, notification_id, notification_created_at)) return notification
def persist_notification( *, template_id, template_version, recipient, service, personalisation, notification_type, api_key_id, key_type, created_at=None, job_id=None, job_row_number=None, reference=None, client_reference=None, notification_id=None, simulated=False, created_by_id=None, status=NOTIFICATION_CREATED, reply_to_text=None, status_callback_url=None, status_callback_bearer_token=None, ): notification_created_at = created_at or datetime.utcnow() if not notification_id: notification_id = uuid.uuid4() notification = Notification( id=notification_id, template_id=template_id, template_version=template_version, to=recipient, service_id=service.id, service=service, personalisation=personalisation, notification_type=notification_type, api_key_id=api_key_id, key_type=key_type, created_at=notification_created_at, job_id=job_id, job_row_number=job_row_number, client_reference=client_reference, reference=reference, created_by_id=created_by_id, status=status, reply_to_text=reply_to_text, status_callback_url=status_callback_url, status_callback_bearer_token=status_callback_bearer_token, ) if notification_type == SMS_TYPE: formatted_recipient = validate_and_format_phone_number_and_allow_international( recipient) recipient_info = get_international_phone_info(formatted_recipient) notification.normalised_to = formatted_recipient notification.international = recipient_info.international notification.phone_prefix = recipient_info.country_prefix notification.rate_multiplier = recipient_info.billable_units # We can't use a sender name/ID if the text is sending to an # international number. At the time of writing, this is because Telstra # won't send to an international number unless sending from the number # associated with the subscription. Additionally, Twilio can send from a # sender name/ID, however, it requires configuration and it depends on # the countries in play. if notification.international: notification.reply_to_text = None elif notification_type == EMAIL_TYPE: notification.normalised_to = format_email_address(notification.to) # if simulated create a Notification model to return but do not persist the Notification to the dB if not simulated: dao_create_notification(notification) if key_type != KEY_TYPE_TEST: if redis_store.get(redis.daily_limit_cache_key(service.id)): redis_store.incr(redis.daily_limit_cache_key(service.id)) if redis_store.get_all_from_hash( cache_key_for_service_template_counter(service.id)): redis_store.increment_hash_value( cache_key_for_service_template_counter(service.id), template_id) increment_template_usage_cache(service.id, template_id, notification_created_at) current_app.logger.info("{} {} created at {}".format( notification_type, notification_id, notification_created_at)) return notification
def skills(): r = RoleQuestion('Data Engineer', { 'Data analysis and synthesis': 'Data analysis and synthesis', 'Communicating between the technical and the non-technical' : 'Communicating between the technical and the non-technical', 'Data development process': 'Data development process', 'Data integration design': 'Data integration design', 'Data modelling': 'Data modelling', 'Programming and build (data engineering)': 'Programming and build (data engineering)', 'Technical understanding (data engineering)': 'Technical understanding (data engineering)', 'Testing': 'Testing' }) r2 = RoleQuestion('Data Scientist', { 'Applied maths, statistics and scientific practices': 1005, 'Data engineering and manipulation': 1034, 'Data science innovation': 1039, 'Developing data science capability': 1043, 'Domain expertise': 1047, 'Programming and build (data science)': 1084, 'Understanding analysis across the life cycle (data science)': 1126 } ) r3 = RoleQuestion('Strategy and Policy', { 'Drafting': 'Drafting', 'Briefing': 'Briefing', 'Research': 'Research', 'Working with ministers': 'Working with ministers', 'Bills and legislation': 'Bills and legislation', 'Policy evaluation': 'Policy evaluation', 'Parliamentary questions/Freedom of Information requests' : 'Parliamentary questions/Freedom of Information requests' }) r4 = RoleQuestion('Generalist skill areas', { 'Commercial awareness': 'Commercial awareness', 'Financial management': 'Financial management', 'People management': 'People management', 'Programme management': 'Programme management', 'Change management': 'Change management', 'Science/engineering policy facing': 'Science/engineering policy facing', 'International policy facing': 'International policy facing' }) families = { 'data': [r, r2, r3, r4] } roles_in_family = families[redis_store.get('family')] seen_roles = int(redis_store.get('roles_seen')) if request.method == 'POST': # user has clicked 'continue' prior_role = roles_in_family[seen_roles-1] redis_store.set(prior_role.name, skill_dump(request.form)) redis_store.rpush('skills', prior_role.name) current_role = roles_in_family[seen_roles] redis_store.incr('roles_seen', 1) # increment the number of roles seen name = current_role.name r = { 'title': name, 'skills': { 'heading': 'Which of the following skills will this role develop?', 'name': 'skills', 'values': current_role.skills, 'for': 'skills' }, 'description': { 'label': 'How will the role deliver these skills?', 'hint': "Please give a brief description of how this role will develop the Fast Streamers skills in the" " areas you've indicated. If you've not ticked anything, there's no need to complete this box.", 'for': 'skills-describe' }, 'skill_level': { 'heading': 'What level of skill will the candidate gain?', 'name': 'skill-level', 'values': { 'Awareness': 1, 'Working': 2, 'Practitioner': 3, 'Expert': 4 }, 'for': 'skill-level', 'hint': "Across all the skills you've indicated, what level of ability do you expect the Fast Streamer to " "have at the end of this post?" } } if seen_roles == len(roles_in_family) - 1: next_step = 'submit.logistical_details' else: next_step = 'submit.skills' return render_template('submit/skills.html', role=r, next_step=next_step)
def get_number(): """排号 涉及办事人员表添加取号记录,办事表查询和添加记录,队列""" # 获取数据 req_dict = request.get_json() subject = req_dict.get('subject', "") # 主题 item = req_dict.get('item', "") # 事项 mobile = req_dict.get('mobile', "") # 电话 idno = req_dict.get('idno', "") # 身份证 addr = req_dict.get('work_addr', "") # 地址 print("++++取号++++", req_dict) # 校验数据 param_keys = ["subject", "item", "mobile", "idno", "work_addr"] param_dict = dict() for i in param_keys: param_dict.__setitem__(i, req_dict.get(i, '')) for key, value in param_dict.items(): if not value: return jsonify(errno=RET.PARAMERR, errmsg="数据不完整,缺少%s" % key) # 判断手机号格式 if not re.match(r"1[34578]\d{9}", mobile): # 表示格式不对 return jsonify(errno=RET.PARAMERR, errmsg="手机号格式错误") # 判断身份证号 if not re.match(r"[1-9]\d{16}[0-9a-zA-Z]", idno): return jsonify(errno=RET.PARAMERR, errmsg="身份证格式错误") # 记录对应主题取号总量 redis_store.incr(addr + subject + "total_number") totle = int( redis_store.get(addr + subject + "total_number").decode("utf-8")) print("取号总量-----------", totle) # 查询办事表检查当事人是否来过 try: current_people = People.query.filter_by(idno=idno).first() current_addr = Addr.query.filter_by(name=addr).first() current_subject = Subject.query.filter_by(name=subject).first() current_item = Item.query.filter_by(name=item).first() current_location = Location.query.filter_by(subject=subject).first() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="数据库错误") # 生成流水号 water_num = current_addr.seq + datetime.now().strftime( "%Y%m%d%H%M%S") + str(current_item.id).rjust(3, '0') # 生成号码 number = current_subject.seq + str((0 + totle * 1) % 1000).rjust(3, '0') # 记录事件 current_business = Business(water_num=water_num, idno=idno, addr=addr, subject=subject, item=item, process=current_item.process, current_process="接件", in_deal=0, is_scene=0, number=number, timeout=current_item.timeout, takan_used_time=0, wait_seconds=0, move_times=0) age = datetime.now().year - int(idno[6:10]) sex = int(idno[16:17]) % 2 try: db.session.add(current_business) if not current_people: current_people = People(idno=idno, mobile=mobile) db.session.add(current_people) db.session.commit() except Exception as e: current_app.logger.error(e) db.session.rollback() return jsonify(errno=RET.DBERR, errmsg="数据库错误") # 添加队列 try: # 发送短信 length = redis_store.llen(addr + subject) location = current_location.location try: result = current_app.config['MSG_SENDER'].send_with_param( 86, mobile, current_app.config['TEMPLATE_NUMBER'], [ number, length, location, datetime.now().strftime('%H:%M:%S') ], sign=current_app.config['SMS_SIGN'], extend="", ext="") # 签名参数未提供或者为空时,会使用默认签名发送短信 pass except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.THIRDERR, errmsg="第三方系统错误") # 添加排队队列 redis_store.rpush(addr + subject, water_num) # 添加排队时间队列 redis_store.rpush(addr + subject + "time", datetime.now().strftime("%H%M%S")) # 添加用户头顶屏幕显示人数 redis_store.rpush( 'usershead', json.dumps({ "subject": subject, "length": length, "show": "true" })) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.SERVERERR, errmsg="内部错误") else: # 返回流水号,号码,位置,等待人数 return jsonify(errno=RET.OK, errmsg="成功", data={ "water_num": water_num, "number": number, "location": location, "wait": length })
def io_player_move(dir): login = session['user'] try: x = int(redis_store.get(login + ':player.x')) y = int(redis_store.get(login + ':player.y')) visible = msgpack.loads(redis_store.get(login + ':visible')) except: return if dir not in DIRECTIONS: return dx, dy = DIRECTIONS[dir] nx, ny = x + dx, y + dy g = at(nx, ny) if (g not in SOLID) and (g != "D" or is_door_opened(login, nx, ny)): x = nx y = ny if update_visible(visible, x, y, first=True): redis_store.set(login + ':visible', msgpack.dumps(visible)) emit('map.visible', msgpack.dumps(visible), room=login) redis_store.set(login + ':player.x', x) redis_store.set(login + ':player.y', y) emit('player.position', (x, y), room=login) if login not in hidden_users: emit('ghost.position', (login, x, y), broadcast=True) if g == "$" and not is_coin_picked(nx, ny): redis_store.incr(login + ':coins') redis_store.set('coin_%d,%d' % (nx, ny), 1) else: if g == 's': # scoreboard emit('scoreboard.view', msgpack.dumps(get_scoreboard())) if g == "D": # closed door prob_id = get_door_problem(nx, ny) if prob_id is None: return prob_data = problems.get(str(prob_id)) if prob_data is None: return if prob_data['type'] in ["team_name", "answer", "guess"]: data = { "name": prob_data['name'], "type": "answer", "id": prob_id, "reward": prob_data['reward'], "cur_reward": get_reward(prob_data['reward']) } if 'statement' in prob_data: data['statement'] = prob_data['statement'] else: if 'internal_name' in prob_data: data['statement_url'] = "/%s.pdf" % prob_data[ 'internal_name'] else: data['statement_url'] = prob_data['statement_url'] emit('problem.view', msgpack.dumps(data)) if prob_data['type'] in ['standard']: data = { "name": prob_data['name'], "type": "standard", "short_name": prob_data['short_name'], "statement_url": "/%s.pdf" % prob_data['internal_name'], "id": prob_id, "reward": prob_data['reward'], "cur_reward": get_reward(prob_data['reward']) } emit('problem.view', msgpack.dumps(data))
def login(): try: res = request.get_json() username = res.get('username') password = res.get('password') Logging.logger.info('request_args:{0}'.format(res)) if not all([username, password]): return jsonify(errno=-1, errmsg='请输入用户名和密码') try: access_counts = redis_store.get('access_' + username) Logging.logger.info('登录错误次数: %s' % access_counts) except Exception as e: Logging.logger.error('errmsg:{0}'.format(e)) return jsonify(errno=-1, errmsg='查询redis失败') # 错误次数不为空 and 错误次数超过了最大值 if access_counts is not None and int(access_counts) >= 5: waiting_time = redis_store.ttl('access_' + username) return jsonify(errno=-1, errmsg='请求错误已超过最大次数,还有%s秒可重新登录' % waiting_time) user = Admin.query.filter_by(username=username).first() if user: if user.status == 0: return jsonify(errno=-1, errmsg='该账号已被停用,请联系管理员') res = hashlib.md5() res.update(password.encode('utf-8')) password = res.hexdigest() if password == user.password: token = user.generate_active_token() user.token = token user.is_login = 1 # 权限状态更新 if user.auth_status == 1: user.auth_status = 0 db.session.add(user) db.session.commit() try: redis_store.delete('access_' + username) except Exception as e: Logging.logger.error('errmsg:{0}'.format(e)) session['user_id'] = user.id session['user_name'] = user.username session['token'] = token data = { "user_id": user.id, "username": username, "token": token, "is_admin": user.is_admin, "status": user.status, "auth_status": user.auth_status } Logging.logger.info('管理员:{0} 登陆成功'.format(username)) return jsonify(errno=0, errmsg="登录成功", data=data) else: # 累加错误次数, 并设置时间 try: # incr:累加错误次数 redis_store.incr('access_' + username) # expire: 第一个参数 key, 第二个参数 过期时间10分钟 redis_store.expire('access_' + username, 600) except Exception as e: Logging.logger.error('errmsg:{0}'.format(e)) return jsonify(errno=-1, errmsg='用户名或密码错误') else: return jsonify(errno=-1, errmsg='用户名不存在') except Exception as e: Logging.logger.error('errmsg:{0}'.format(e)) return jsonify(errno=-1, errmsg='网络异常')
def persist_notification(*, template_id, template_version, recipient, service, personalisation, notification_type, api_key_id, key_type, created_at=None, job_id=None, job_row_number=None, reference=None, client_reference=None, notification_id=None, simulated=False, created_by_id=None, status=NOTIFICATION_CREATED, reply_to_text=None, billable_units=None, postage=None, document_download_count=None, updated_at=None): notification_created_at = created_at or datetime.utcnow() if not notification_id: notification_id = uuid.uuid4() notification = Notification( id=notification_id, template_id=template_id, template_version=template_version, to=recipient, service_id=service.id, personalisation=personalisation, notification_type=notification_type, api_key_id=api_key_id, key_type=key_type, created_at=notification_created_at, job_id=job_id, job_row_number=job_row_number, client_reference=client_reference, reference=reference, created_by_id=created_by_id, status=status, reply_to_text=reply_to_text, billable_units=billable_units, document_download_count=document_download_count, updated_at=updated_at) if notification_type == SMS_TYPE: formatted_recipient = validate_and_format_phone_number( recipient, international=True) recipient_info = get_international_phone_info(formatted_recipient) notification.normalised_to = formatted_recipient notification.international = recipient_info.international notification.phone_prefix = recipient_info.country_prefix notification.rate_multiplier = recipient_info.billable_units elif notification_type == EMAIL_TYPE: notification.normalised_to = format_email_address(notification.to) elif notification_type == LETTER_TYPE: notification.postage = postage notification.international = postage in INTERNATIONAL_POSTAGE_TYPES notification.normalised_to = ''.join(notification.to.split()).lower() # if simulated create a Notification model to return but do not persist the Notification to the dB if not simulated: dao_create_notification(notification) # Only keep track of the daily limit for trial mode services. if service.restricted and key_type != KEY_TYPE_TEST: if redis_store.get(redis.daily_limit_cache_key(service.id)): redis_store.incr(redis.daily_limit_cache_key(service.id)) current_app.logger.info("{} {} created at {}".format( notification_type, notification_id, notification_created_at)) return notification
def login(): """ 用户登录 用户名、 密码 :return: """ #index_url = url_for('.index', _external=True) #if session.get('id'): # return redirect(index_url) #if request.method == 'GET': # return render_template('login.html') # 获取用户传输数据 request_data = request.json username = request_data.get('username') password = request_data.get('password') if not all([username, password]): #return render_template('login.html', message='缺少必要参数') return jsonify(params_error(message='缺少必要参数')) # 获取用户登录IP user_ip = request.remote_addr try: access_nums = redis_store.get('access_num_%s' % user_ip) except Exception as e: current_app.logger.error(e) else: if access_nums and int(access_nums) >= 5: #return render_template('login.html', message='错误次数过多,请稍后重试') return jsonify(unauth_error(message='错误次数过多,请稍后重试')) # 从数据库查询用户对象 try: user_obj = User.query.filter_by(username=username).first() except Exception as e: current_app.logger.error(e) #return render_template('login.html', message='获取用户信息失败') return jsonify(server_error(message='获取用户信息失败')) # 取出用户密码与数据库密码对比 if not user_obj or not user_obj.check_password(password): # 如果用户不存在或者用户密码不正确,返回错误消息,并记录错误次数 try: # redis的incr可以对字符串类型数据进行加1操作,如果数据开始不存在,则默认设置为1 redis_store.incr('access_num_%s' % user_ip) redis_store.expire('access_num_%s' % user_ip, 600) # 数据保存600秒 except Exception as e: current_app.logger.error(e) #return render_template('login.html', message='用户名或密码错误') return jsonify(unauth_error(message='用户名或密码错误')) # 登录成功 session['username'] = username session['nickname'] = user_obj.nickname session['id'] = user_obj.id # 更改用户在线状态 user_obj.state = 1 try: db.session.commit() except Exception as e: current_app.logger.error(e) #return render_template('login.html', message='登录异常') return jsonify(server_error('登录异常')) #return redirect(index_url) return jsonify(success(data=user_obj.to_dict(), message='用户登录成功'))