def super_cleanLog(): """ 超级管理员清除服务器的所有用户行为日志errlogs.txt :return: json结果 """ username = request.form.get("username", type=str, default="") if session.get("isLogin") and session.get("username") == username: result = DB_Sync.query_redis(username) usertype = result["data"]["USER_TYPE"] userlock = result["data"]["USER_LOCK"] # 超级用户且没有被人为锁定 if usertype == "super" and userlock == 0: if cleanLogging(): code = "0" msg = "文件清除成功" logger.info("%s用户删除日志成功,具有权限为%s,锁定为%d" % (username, usertype, userlock)) else: code = "1" msg = "文件异常,无法清除" logger.error("%s用户删除日志失败,原因:文件异常,无法清除" % username) else: code = "-1" msg = "您没有权限执行该操作" else: code = "-1" msg = "您当前不处于登录状态,请先登录" resp = jsonify(code=code, msg=msg) resp.set_cookie("datetime", getlocaltime()) return resp
def refresh_redis(username: str): """从mysql刷新数据到Redis :param username: 需要刷新的用户名 :return bool """ # db = pymysql.Connect(host='localhost', user='******', password=mysql_passwd, # database=mysql_base, charset='utf8') # 通过docker部署需要使用下面的配置连接 db = pymysql.Connect(host=mysql_host, user='******', password=mysql_passwd, database=mysql_base, charset='utf8') cursor = db.cursor(cursor=pymysql.cursors.DictCursor) myname = "\"{0}\"".format(username) try: sql = 'select USER_TYPE, USER_LOCK, USER_NAME, USER_PASSWD, USER_SALT, USER_MAIL, SUBMISSION_DATE from {0} where USER_NAME={1};'.format( mysql_table, myname) print("refresh_redis", sql) cursor.execute(sql) result_mysql = cursor.fetchall() print("refresh redis from mysql", result_mysql) # 原来redis存有数据需要清空 if dict_into_redis(result_mysql[0]['USER_NAME'], result_mysql[0]): flag = True logger.info("%s用户同步到redis刷新成功" % username) else: flag = False except Exception as e: db.rollback() flag = False logger.error("%s用户同步到redis刷新失败,原因:%s" % (username, e)) db.close() r.close() return flag
def send_email_capture(app, mail, email, capture): """用于注册时候异步发送邮件验证码 注意频繁发送邮件可能会导致550 MailBox not found and access denied错误 :param app: Flask实例对象 :param mail: Flask的MAIL实例 :param email: 合法用户注册的email :param capture: 随机数字验证码 :return: bool """ flag = False msg = Message(subject='Spider用户登录邮箱验证码:', recipients=[email]) msg.html = '<!DOCTYPE HTML><html><head></head><body><p><font size="5",color=black>尊敬的用户: 您好!</font></p>      您 <font color="#ff9955">Spider</font> 邮箱登录的验证码为: <span style="border-bottom: 1px dashed rgb(204, 204, 204);"><font size="5" color =green><b>{0}</b></font></span>有效期限为<b><font color ="rgb(204, 195, 175)">10分钟</font></b>,请尽快前往注册。(<i>如果不是您提交的申请,请忽略</i>)<p>      感谢您的使用。</p></body></html>'.format( capture) thread = Thread(target=send_async_email, args=[app, mail, msg]) # .start()会安排对象在另外一个单独线程中运行run()方法,是异步执行。run()是普通的同步执行 try: thread.start() flag = True print("{0} 邮件发送成功".format(email)) logger.info("%s邮箱验证码%s发送成功" % (email, capture)) except Exception as e: flag = False print("{0} 邮件发送失败".format(email)) logger.error("%s邮箱验证码%s发送失败,原因:%s" % (email, capture, e)) return flag
def super_Download_LogDB(): """ super管理员下载数据库备份文件和errlogs日志 :return: json结果 """ username = request.form.get('username') filename = request.form.get('filename', type=str, default='') # 是否处于登录状态 if session.get('username') == username and session.get('isLogin'): # 判断是否是super权限以及被人为锁定状态 result = DB_Sync.query_redis(username) usertype = result['data']['USER_TYPE'] userlock = result['data']['USER_LOCK'] if usertype == 'super' and userlock == 0: logger.info('super用户%s下载了文件%s' % (username, filename)) print('server path:', serverlogs_path) return send_from_directory( directory=serverlogs_path, filename=filename.encode('utf-8').decode('utf-8'), as_attachment=True) else: return abort(401) else: code = "-1" msg = "您当前不处于登录状态,请先登录" return jsonify(code=code, msg=msg)
def register(): """判断为新用户,新用户注册,需要结合传递过来的邮箱(邮箱要唯一)以及邮箱验证码,用户名(唯一)和密码 :return: json结果 """ if request.method == "POST": email = request.form.get("email", type=str, default="") username = request.form.get("username", type=str, default="") passwd = request.form.get("passwd", type=str, default="") capture = request.form.get("capture", type=str, default="") # 用户名,密码,验证码, 邮箱为空 if not (username and passwd and email and capture): code = "-1" msg = "用户输入了空参数" # 查询本地是否有同名用户名和邮箱 else: # 本地数据库不存在已注册相关用户名和邮箱信息,核实验证码注册 if not DB_Sync.exist_UserName_email(username, email): captureCode = DB_Sync.query_redis_Capture( email) # 如果email没找到,capturecode为None而不是"" if captureCode == capture: code = "0" msg = "注册成功" # 新用户写入数据库 # 先对用户密码加密,需要盐 salt = create_Salt() passwd = computePW(passwd, salt) # 新用户入库 isOk = DB_Sync.sync_redis_insert(username, passwd, salt, email) if not isOk: code = "-1" msg = "新用户注册入库失败" else: # 刷新同步到redis DB_Sync.refresh_redis(username) session['isLogin'] = True session['username'] = username # 最后创建该用户的文件夹 iscreate, user_home_str = User_Action.create_user_homedir( username) if iscreate: logger.info("为新注册用户%s创建文件夹成功" % username) else: logger.error("为新注册用户%s创建文件夹失败" % username) else: code = "-1" msg = "验证码失效或错误" # 本地已存在相关信息用户信息 else: code = "-1" msg = "用户名或邮箱已存在,请重新输入" else: code = '-1' msg = '{} Method is not allowed !'.format(request.method) resp = jsonify(code=code, msg=msg) resp.set_cookie("datetime", getlocaltime()) return resp
def query_redis(username: str): """读取Redis数据或者Mysql,然后返回json :param username: 需要查询的用户名 :return: json格式结果 """ # 与Redis建立连接(连接池) # result_redis返回的结果是字符串,需要json.loads()才返回dict # db = pymysql.Connect(host='localhost', user='******', password=mysql_passwd, # database=mysql_base, charset='utf8') # 通过docker部署需要使用下面的配置连接 db = pymysql.Connect(host=mysql_host, user='******', password=mysql_passwd, database=mysql_base, charset='utf8') cursor = db.cursor(cursor=pymysql.cursors.DictCursor) result_json = {"code": '', "data": '', "msg": ''} # 查不到返回None 对应布尔值为False result_redis = r.get(username) print("query redis结果", result_redis) # 如果数据存在则输出,不存在则重新查询mysql数据库 if result_redis: # 成功返回json数据 result_json["code"] = '0' result_json["data"] = loads(result_redis) result_json["msg"] = 'Success' logger.info("查询redis中%s用户数据为%s:" % (username, result_redis)) else: # 连接mysql # 查询数据库 userinfo 表格中是否存有数据 sql = "select USER_TYPE, USER_LOCK, USER_NAME, USER_PASSWD, USER_SALT, USER_MAIL, SUBMISSION_DATE from {0} where USER_NAME='{1}';".format( mysql_table, username) print('检查未知列字段sql', sql) cursor.execute(sql) result_mysql = cursor.fetchall() # print(result_mysql) # print("result结果:%s" % result_mysql) # 数据库没有数据返回Failed;有数据写入Redis并返回 if not result_mysql: print('Mysql中没有该 %s 用户' % username) result_json["code"] = '-1' result_json["msg"] = 'Failed' logger.warning("MySQL中无%s用户" % username) else: # 查询到数据的时候写入Redis存储并设置过期时间(秒) print("Mysql中查询到{0}用户数据为: {1}".format(username, result_mysql)) if dict_into_redis(result_mysql[0]['USER_NAME'], result_mysql[0]): print("{}写入Redis存储成功".format(username)) result_redis = dict_outof_redis(username) result_json["code"] = '1' result_json["data"] = result_redis result_json["msg"] = 'Success' logger.info("MySQL写入redis中%s用户数据为%s:" % (username, result_redis)) db.close() r.close() return result_json
def forgetPWD(): """用户名和邮箱以及邮箱的验证码和新密码,查询本地用户名和邮箱是否对应,是发送验证码,然后检验验证码 :return: json结果 """ email = request.form.get("email", type=str, default="") username = request.form.get("username", type=str, default="") captureCode = request.form.get("capture", type=str, default="") new_passwd = request.form.get("new_passwd", type=str, default="") # 本地数据库无对应数据,修改不了 if not DB_Sync.exist_UserName_email(username, email): code = "-1" msg = "用户名或者邮箱错误" # 本地有数据可以修改,核对验证码 else: # 判断根据邮箱查到的用户名是否一致,避免修改他人的数据 # 验证码一致,而且email和用户名也对应.(默认不考虑用户忘记用户名的情况) isConsist = DB_Sync.is_consistent(email, username) if captureCode == DB_Sync.query_redis_Capture(email) and isConsist: result = DB_Sync.query_redis(username) # 根据用户名查询到了结果(salt) print(result) salt = result["data"]['USER_SALT'] compute_new_pwd = computePW(new_passwd, salt) isOK = DB_Sync.sync_redis_insert(username, compute_new_pwd, salt, email) print("is ok", isOK) if isOK: code = "0" msg = "密码重置成功,请用新的密码登录" logger.info("%s用户密码修改成功" % username) # 修改密码后需要清除session数据 session["isLogin"] = False session.clear() if DB_Sync.refresh_redis(username): print("redis刷新成功...") else: print("redis刷新失败...") else: code = "-1" msg = "密码重置失败,请重试" print("{0}用户重置密码失败".format(username)) logger.error("%s用户重置密码失败" % username) else: code = "-1" msg = ("验证码失效" if isConsist else "用户名密码不一致") logger.error("%s用户重置密码失败,原因:%s" % (username, msg)) resp = jsonify(code=code, msg=msg) resp.set_cookie("datetime", getlocaltime()) return resp
def deleteUSER(): """ 管理员或者super用户在用户管理界面删除其他用户(低权限用户) :return: """ tup = ("user", "admin", "super") # 用下标 0, 1, 2 来比较权限的大小!! # 当前修改者属性 username = request.form.get("username", type=str, default="") # 被修改者的属性 othername = request.form.get('othername', type=str, default="") otheremail = request.form.get("otheremail", type=str, default="") result = DB_Sync.query_redis(othername) # print(result) othertype = result["data"]["USER_TYPE"] # 判断当前用户是否在线 if session.get("username") == username and session.get('isLogin'): # 获取当前用户的权限和锁定情况 result = DB_Sync.query_redis(username) usertype = result["data"]["USER_TYPE"] userlock = result["data"]["USER_LOCK"] # 判断当前用户是否有权限删除,自己删除不了自己 if userlock == 0 and tup.index(usertype) > tup.index(othertype): is_delete = DB_Sync.sync_redis_delete(othername, otheremail) if is_delete: code = "0" msg = "用户账号注销成功" logger.info("%s管理员注销%s用户成功" % (username, othername)) # 用户删除成功时候,删除用户目录 if User_Action.remove_user_homedir(username): logger.warning("注销删除%s用户文件目录数据成功" % username) else: logger.error("注销删除%s用户文件目录数据失败" % username) else: code = "-1" msg = "用户账号注销失败" logger.error("%s管理员注销%s用户失败" % (username, othername)) else: code = "1" msg = "您没有权限执行操作" else: code = "-1" msg = "您当前不处于登录状态,请先登录" resp = jsonify(code=code, msg=msg) resp.set_cookie("datetime", getlocaltime()) return resp
def sync_redis_delete(username: str, email: str): """MySQL数据库删除数据同步到Redis :param username: 需要删除的用户名 :param email: 用户的邮箱 :return: bool """ # db = pymysql.Connect(host='localhost', user='******', password=mysql_passwd, # database=mysql_base, charset='utf8') # 通过docker部署需要使用下面的配置连接 db = pymysql.Connect(host=mysql_host, user='******', password=mysql_passwd, database=mysql_base, charset='utf8') cursor = db.cursor(cursor=pymysql.cursors.DictCursor) flag = True # 标记操作成功或失败 # 先查询本地mysql是否有用户数据记录,有的话则删除,然后同步到redis;没有则不执行任何操作返回true if not exist_UserName_email(username, email): r.close() db.close() flag = True else: # 有用户数据,直接删除mysql和Redis print("mysql本地有 %s 用户,直接删除并同步" % username) isRedis = False try: # 直接删除数据库 sql = 'delete from {0} where USER_NAME=%s;'.format(mysql_table) cursor.execute(sql, [username]) # sql = 'Alter table {0} AUTO_INCREMENT=1;'.format(mysql_table) # cursor.execute(sql) db.commit() isRedis = True # 删除redis缓存的用户数据 r.delete(username) logger.info("本地有%s用户数据删除成功" % username) except Exception as e: print("删除Redis用户缓存失败" if isRedis else "删除MySQL用户数据失败") db.rollback() flag = False logger.error("本地有%s用户数据删除失败,原因%s" % (username, e)) db.close() r.close() return flag
def eraseUSER(): """ 清空redis数据并删除本地数据库用户信息,同步redis :return: json结果 """ username = request.form.get("username", type=str, default="") email = request.form.get("email", type=str, default="") captureCode = request.form.get("capture", type=str, default="") # 判断是否处于登录状态 if session["isLogin"] and session.get("username") == username: # 判断验证码是否正确 isConsist = DB_Sync.is_consistent(email, username) if captureCode == DB_Sync.query_redis_Capture(email) and isConsist: # 删除redis数据,然后删除本地mysql数据 isDelete = DB_Sync.sync_redis_delete(username, email) if isDelete: code = "0" msg = "用户账号注销成功" session["isLogin"] = False # 清除服务器数据 session.clear() logger.info("%s用户账号注销成功" % username) # 用户删除成功时候,删除用户目录 if User_Action.remove_user_homedir(username): logger.warning("注销删除%s用户文件目录数据成功" % username) else: logger.error("注销删除%s用户文件目录数据失败" % username) else: code = "-1" msg = "用户账号注销失败" logger.warning("%s用户账户注销失败" % username) else: code = "-1" msg = "验证码不一致" logger.info("%s用户输入验证码不一致" % username) # 当前不是处于登录状态 else: code = "-1" msg = "您当前不处于登录状态,请先登录" logger.warning("%s用户删除数据失败,原因:当前处于非登录状态" % username) resp = jsonify(code=code, msg=msg) resp.set_cookie("datetime", getlocaltime()) return resp
def super_Handle_LogDB(): """ super清空errlogs.txt和删除db备份文件(正常来说应该保留最近一次备份的不允许删除,本项目不考虑此情况) :return: json结果 """ filename = request.form.get("filename", type=str, default="") username = request.form.get("username", type=str, default="") if session.get("isLogin") and session.get("username") == username: result = DB_Sync.query_redis(username) usertype = result["data"]["USER_TYPE"] userlock = result["data"]["USER_LOCK"] # 超级用户且没有被人为锁定 if usertype == "super" and userlock == 0: # 如果是日志则清空 if filename == serverlogs_name: if cleanLogging(): code = "0" msg = "文件清空成功" logger.info("%s用户删除日志成功,具有权限为%s,锁定为%d" % (username, usertype, userlock)) else: code = "1" msg = "文件异常,无法清除" logger.error("%s用户删除日志失败,原因:文件异常,无法清除" % username) # 如果是备份文件则删除 else: global serverlogs_path User_Action.fileDelete(serverlogs_path + r'\{}'.format(filename)) code = "0" msg = "文件删除成功" logger.info("%s用户删除文件%s成功,具有权限为%s,锁定为%d" % (username, filename, usertype, userlock)) else: code = "-1" msg = "您没有权限执行该操作" else: code = "-1" msg = "您当前不处于登录状态,请先登录" resp = jsonify(code=code, msg=msg) resp.set_cookie("datetime", getlocaltime()) return resp
def quit(): """ get方式退出登录并清除session数据 :return: json结果 """ username = session.get("username") print(username) print('session["isLogin"]='******'csrf_token') session.clear() session['csrf_token'] = csrf_token resp = jsonify(code="0", msg="清除服务端数据成功!") logger.info("%s用户退出成功,已经清除服务端session数据" % username) return resp else: resp = jsonify(code="1", msg="您已经退出登录") logger.error("拒绝响应%s用户,原因是: 您已经退出登录" % username) return resp
def is_consistent(email: str, username: str): """根据email查询是否有该用户 :param email: 前端传来的需要查询的email :param username: 根据email需要核实的用户名 :return: bool """ # db = pymysql.Connect(host='localhost', user='******', password=mysql_passwd, # database=mysql_base, charset='utf8') # 通过docker部署需要使用下面的配置连接 db = pymysql.Connect(host=mysql_host, user='******', password=mysql_passwd, database=mysql_base, charset='utf8') cursor = db.cursor(cursor=pymysql.cursors.DictCursor) # email = "\'{}\'".format(email) flag = True sql = "select USER_NAME from {0} where USER_MAIL='{1}';".format( mysql_table, email) try: cursor.execute(sql) result_mysql = cursor.fetchall() # 查询到本地数据库存在该数据的时候 if result_mysql and result_mysql[0]['USER_NAME'] == username: flag = True logger.info("email:%s和用户名:%s一致" % (email, username)) # 该email未注册用户,查不到数据 else: print("查询email{0}和用户名{1}的结果为:{1}".format( email, username, result_mysql[0]['USER_NAME'])) flag = False logger.waring("email:%s和用户名:%s不一致" % (email, username)) except: print("查询email{0}和用户名{1}的结果为:{1}".format(email, username, result_mysql[0]['USER_NAME'])) db.rollback() db.close() return flag
def handleITSpider(username: str, url: str, path: str): """ 核心业务ITSpider.py爬取,通过全局函数来保存爬取的状态,解决函数无法操作sessio的问题 :param username: 执行操作的用户名 :param url: 需要爬取的网址 :param path: 用户文件夹下的绝对路径,保存爬取过的文件txt :return: 没有return(在ThreadWorker里面,return没有意义) """ myfilename = "" try: myfilename = runSpider(url, path) except Exception as e: logger.error('%s用户爬取%s过程出错,原因是%s' % (username, url, e)) if myfilename: # 全局变量解决任务完成后,函数无法操作session的问题 global spider_file_status spider_file_status = True global spider_file_name spider_file_name = myfilename logger.info('%s用户请求爬取%s成功' % (username, url)) else: logger.info('%s用户请求爬取%s失败' % (username, url))
def create_redis_Capture(email: str, capturecode: str): """用redis保存十分钟时长的用户验证码,返回插入成功或者失败 :param email: 用户邮箱 :param capturecode: 已发送的用户验证码 :return: bool """ isRedis = False # 十分钟内再次请求需要删除之前的验证码 pre_result = r.get(email) if pre_result: r.delete(email) try: r.set(email, capturecode) r.expire(name=email, time=max_EmailCodeTime) isRedis = True logger.info("redis保存%s邮箱的十分钟验证码%s成功" % (email, capturecode)) except: isRedis = False print("redis保存十分钟验证码失败") logger.info("redis保存%s邮箱的十分钟验证码%s失败" % (email, capturecode)) r.close() return isRedis
def login(): """ 前端登录请求post请求,从数据库中验证params完整性和正确性,并设置相应的cookies和session :return: json结果 """ logintime = "" if request.method == 'POST': # 这里进行了折衷的处理为了实现登录顶掉他人登录的需求.(人性化的做法应该是提示在他处登录,询问要不要踢掉或者在其他地方先推出,这边在登陆) quit() print(request.form.get("username", type=str, default="")) # 判断用户名密码是否正确 username = request.form.get("username", type=str, default="") passwd = request.form.get("passwd", type=str, default="") if username == "" or passwd == "": code = "-1" msg = "用户名或密码为空或不合法" # 用户名不空查询后端数据 else: result = DB_Sync.query_redis(username) # 用户不存在 if result["code"] == "-1": code = "-1" msg = "用户名或密码错误" # 用户存在 result["code"]返回0,1 else: salt = "" # 判断密码是否正确 if result["data"] != "": salt = result["data"]["USER_SALT"] localPW = result["data"]["USER_PASSWD"] print("redis data", result["data"]) print("computePasswd", computePW(passwd, salt)) # 验算用户传递的密码是否和数据库中保存的一致 isConsistent = checkPW(computePW(passwd, salt), localPW) # 密码输入正确 if isConsistent: code = "0" msg = "登录验证成功" session["logintime"] = getlocaltime() if session.get("isLogin"): logger.warning("%s用户登录失败,原因是已在其他地方登录" % username) return jsonify(code="-1", msg="您已在其他地方登录") session["isLogin"] = True session["username"] = username logintime = getlocaltime() logger.info("%s用户登录成功" % username) # 密码输入错误 else: code = "-1" msg = "用户名或密码错误" logger.warning("%s用户登录输入密码错误,登录失败" % username) resp = jsonify(code=code, msg=msg) resp.set_cookie('datetime', getlocaltime()) resp.set_cookie('logintime', logintime) resp.set_cookie('username', request.form.get("username", type=str, default="null"), expires=max_ageTime) # max_age单位是秒,过期时间 return resp # 如果是其他请求方法 else: resp = jsonify(code='-1', msg='{} Method is not allowed !'.format(request.method)) resp.set_cookie('datetime', getlocaltime()) resp.set_cookie('logintime', logintime) resp.set_cookie('username', request.form.get("username", type=str, default="null"), expires=max_ageTime) # max_age单位是秒,过期时间 return resp