以社工库为例的简单web前后端分离项目搭建

所谓的社工库可能是最简单的web项目了,没有登录、注册、权限等逻辑,当然这里只是最简单的那种。今天拿这个为例聊下前后端分离项目的结构。

下面是Github上搜到的社工库项目https://github.com/Leezj9671/socialdb_vue_flask,socialdb_vue_flask,同样只是技术说明,不提供数据,并做了下小修改:添加了级联搜索多进程并发写入数据库

环境:前端 Nodejs Vue

后端 Python Flask

数据库 MongoDB

常规小的web项目,比如Flask + Bootstrap,不同的是可以前后端约定后接口后分别独立开发调试,然后部署整合成一个项目

原作者的前端页面

image
image

后端接口

api_main.py

'''
api
存在问题:

  • 并发请求时,且前一请求正在查询会导致卡死
    '''

import time
from pymongo import MongoClient
from flask import Flask, request, jsonify, redirect, url_for
from flask_restful import Api, Resource, reqparse
from conf.config import MongoDBConfig

app = Flask(name)
client = MongoClient(MongoDBConfig.g_server_ip, MongoDBConfig.g_server_port)
db = client[MongoDBConfig.g_db_name]

def response_cors(data=None, datacnts=None, status=None):
'''为返回的json格式进行跨域请求'''
if data:
resp = jsonify({"status": status, "data": data, "datacounts": datacnts})
else:
resp = jsonify({"status": status})
resp.headers['Access-Control-Allow-Origin'] = '*'
return resp

class Person(Resource):
'''人员类'''

def get(self, user=None, email=None, password=None, passwordHash=None, source=None, xtime=None):

该处可能存在安全问题,做出限制会更好

print(user)

parser = reqparse.RequestParser()
parser.add_argument('limit', type=int, help='Show [limitn] datas in one page')
parser.add_argument('skip', type=int, help='Skip [skipn] datas')
args = parser.parse_args()
limitn = 10 if args['limit'] is None else args['limit']
skipn = 0 if args['skip'] is None else args['skip']

data用于存储获取到的信息

data = []
datacnts = 0

待改进

if user:
persons_info = db.person.find({"user": {"options": "regex": user, "i"}}, {"_id": 0}).count()

elif email:
persons_info = db.person.find({"email": {"options": "regex": email, "i"}}, {"_id": 0}).count()

elif password:
persons_info = db.person.find({"password": {"options": "regex": password, "i"}}, {"_id": 0}).count()

elif passwordHash:
persons_info = db.person.find({"passwordHash": {"options": "regex": passwordHash, "i"}}, {"_id": 0}).count()

elif source:

persons_info = db.person.find({"source": {"options":"$i"}}, {"_id": 0}).limit(limitn).skip(skipn)

elif xtime:

persons_info = db.person.find({"xtime": {"options":"$i"}}, {"_id": 0}).limit(limitn).skip(skipn)

else:

限制只能查询10个

persons_info = db.person.find({}, {"_id": 0, "update_time": 0}).limit(10)

for person in persons_info:
data.append(person)

判断有无数据返回

if data:
return response_cors(data, datacnts, "ok")
else:
return response_cors(data, datacnts, "not found")

def post(self):
'''
以json格式进行提交文档
'''
data = request.get_json()
if not data:
return {"response": "ERROR DATA"}
else:
user = data.get('user')
email = data.get('email')

if user and email:
if db.person.find_one({"user": user, "email": email}, {"_id": 0}):
return {"response": "{{} {} already exists.".format(user, email)}
else:
data.create_time = time.strftime('%Y%m%d', time.localtime(time.time()))
db.person.insert(data)
else:
return redirect(url_for("person"))

暂时关闭高危操作

def put(self, user, email):

'''

根据user和email进行定位更新数据

'''

data = request.get_json()

db.person.update({'user': user, 'email': email},{'$set': data},)

return redirect(url_for("person"))

def delete(self, email):

'''

email作为唯一值, 对其进行删除

'''

db.person.remove({'email': email})

return redirect(url_for("person"))

class Info(Resource):
'''个人信息类'''

def get(self, id=None, name=None, sex=None, qq=None, phonenumber=None):

该处可能存在安全问题,做出限制会更好

parser = reqparse.RequestParser()
parser.add_argument('limit', type=int, help='Show [limitn] datas in one page')
parser.add_argument('skip', type=int, help='Skip [skipn] datas')
args = parser.parse_args()
limitn = 10 if args['limit'] is None else args['limit']
skipn = 0 if args['skip'] is None else args['skip']

data用于存储获取到的信息

data = []
datacnts = 0

待改进

if id:
my_info = db.info.find({"id": id}, {"_id": 0}).limit(limitn).skip(
skipn)
datacnts = db.info.find({"id": id}, {"_id": 0}).count()

elif name:
my_info = db.info.find({"name": {"options": "regex": name, "i"}}, {"_id": 0}).count()

elif sex:
my_info = db.info.find({"sex": {"options": "regex": sex, "i"}}, {"_id": 0}).count()

elif qq:
my_info = db.info.find({"qq": qq},
{"_id": 0}).limit(limitn).skip(skipn)
datacnts = db.info.find({"qq": qq}, {"_id": 0}).count()

elif phonenumber:
my_info = db.info.find({"phonenumber": phonenumber},
{"_id": 0}).limit(limitn).skip(skipn)
datacnts = db.info.find({"phonenumber": phonenumber}, {"_id": 0}).count()

else:

限制只能查询10个

my_info = db.info.find({}, {"_id": 0, "update_time": 0}).limit(10)

for person in my_info:
data.append(person)

判断有无数据返回

if data:
return response_cors(data, datacnts, "ok")
else:
return response_cors(data, datacnts, "not found")

def post(self):
'''
以json格式进行提交文档
'''
data = request.get_json()
if not data:
return {"response": "ERROR DATA"}
else:
user = data.get('user')
email = data.get('email')

if user and email:
if db.person.find_one({"user": user, "email": email}, {"_id": 0}):
return {"response": "{{} {} already exists.".format(user, email)}
else:
data.create_time = time.strftime('%Y%m%d', time.localtime(time.time()))
db.person.insert(data)
else:
return redirect(url_for("person"))

暂时关闭高危操作

def put(self, user, email):

'''

根据user和email进行定位更新数据

'''

data = request.get_json()

db.person.update({'user': user, 'email': email},{'$set': data},)

return redirect(url_for("person"))

def delete(self, email):

'''

email作为唯一值, 对其进行删除

'''

db.person.remove({'email': email})

return redirect(url_for("person"))

class Analysis(Resource):
'''
分析功能
'''

def get(self, type_analyze):
'''
type为分析类型,包括邮箱后缀、泄漏来源、泄漏时间
type: [suffix_email, source, xtime, create_time]
'''
if type_analyze in ["source", "xtime", "suffix_email", "create_time"]:
pipeline = [{"sum": 1}}}]
return response_cors(list(db.person.aggregate(pipeline)), None, "ok")

else:
return response_cors("use /api/analysis/[source, xtime, suffix_email] to get analysis data.", None, "error")

class Getselector(Resource):
'''
获取级联数据功能
'''

def get(self):
'''
type为分析类型,包括邮箱后缀、泄漏来源、泄漏时间
type: [suffix_email, source, xtime, create_time]
'''
subject = [
{
"id": 1,
"name": "账密",
"select": "find",
"obj": [
{
"id": 3,
"name": "用户名",
"select": "user"
},
{
"id": 4,
"name": "密码",
"select": "password"
},
{
"id": 5,
"name": "邮箱",
"select": "email"
},
{
"id": 6,
"name": "哈希密码",
"select": "passwordHash"
}
]
},
{
"id": 2,
"name": "身份信息",
"select": "info",
"obj": [
{
"id": 7,
"name": "手机号",
"select": "phonenumber"
},
{
"id": 8,
"name": "QQ",
"select": "qq"
},
{
"id": 9,
"name": "身份证",
"select": "id"
},
{
"id": 10,
"name": "姓名",
"select": "name"
}
]
}
]
return response_cors(subject, None, "ok")

添加api资源

api = Api(app)
api.add_resource(Person, "/api/find")
api.add_resource(Person, "/api/find/user/", endpoint="user")
api.add_resource(Person, "/api/find/email/", endpoint="email")
api.add_resource(Person, "/api/find/password/", endpoint="password")
api.add_resource(Person, "/api/find/passwordHash/", endpoint="passwordHash")
api.add_resource(Person, "/api/find/source/", endpoint="source")
api.add_resource(Person, "/api/find/time/", endpoint="xtime")
api.add_resource(Info, "/api/info")
api.add_resource(Info, "/api/info/id/", endpoint="id")
api.add_resource(Info, "/api/info/name/", endpoint="name")
api.add_resource(Info, "/api/info/sex/", endpoint="sex")
api.add_resource(Info, "/api/info/qq/", endpoint="qq")
api.add_resource(Info, "/api/info/phonenumber/", endpoint="phonenumber")
api.add_resource(Analysis, "/api/analysis/", endpoint="type_analyze")
api.add_resource(Getselector, "/api/get_selector")

if name == 'main':
app.run(host='0.0.0.0', debug=True)

后端起了Flask服务器,默认监听5000端口,主要使用Flask Restful API编写,负责处理接口逻辑+数据库操作,其他还有写入数据库操作。

在 Person类Get方法中编写get请求业务逻辑

前端也相当精简,甚至简陋,只有两个component,search.vue(搜索)和 Analysis.vue(分析)

其中search.vue加了级联前端和请求级联数据方法(created /get_selector方法)


安装配置方法参考项目中README.md就好,原作者使用网易52G数据测试,我这边拿Q绑数据测试,对应的身份信息-手机号,身份信息collection名是info,具体字段名在前端页面里面,id 身份证 姓名 性别 地址 qq 手机号

 {{ item.id }}
{{ item.name }}
{{ item.sex }}
{{ item.address }}
{{ item.qq }}
{{ item.phonenumber }}

image-20210511202457846

Github链接:https://github.com/wdsjxh/socialdb_vue_flask_new

你可能感兴趣的:(以社工库为例的简单web前后端分离项目搭建)