我的设置如下:
- Flask应用程序与自定义域和Nginx,使其更容易HTTPS流量
- flask 请求数据的FastApi
我有一个返回授权令牌的登录页面(可能不是最好的安全性,但测试小型项目),我的登录方法在Flask中能够捕获这个auth_token并重定向到另一个使用auth_token作为查询参数的页面。
每个函数的代码如下:
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
# Forward the request to the FastAPI application running on port 8000
try:
user = request.form.get('user')
password = request.form.get('password')
# Make a request to the FastAPI endpoint
response = requests.post('http://python-fastapi:8000/login', params={'user': user, 'password': password})
response_data = response.json()
if response.status_code != 200:
# Catch detail in HTTPException
raise Exception(response_data["detail"])
return redirect("/dashboard?auth_token="+response_data["token"])
except Exception as e:
return jsonify({"status": "error", "message": str(e)}), 500
else:
return render_template("login.html")
@app.route("/dashboard")
def dashboard():
auth_token = request.get("auth_token")
# Get important information from the FastAPI application and render it in the dashboard
try:
response = requests.get('http://python-fastapi:8000/datasets', params={'auth_token': auth_token})
if response.ok:
data = response.json()
return {"data": data}
else:
data = response.json()
return {"error": data["detail"] + str(auth_token)}
except Exception as e:
return {"error": str(e)}
如果有用的话,我的nginx配置:
server {
listen 80;
server_name automl.ddns.net;
# This just redirects if you go through http
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name automl.ddns.net;
resolver 127.0.0.11 valid=10s;
resolver_timeout 5s;
ssl_certificate /etc/letsencrypt/live/automl.ddns.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/automl.ddns.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Redirect any HTTP requests to HTTPS
if ($scheme != "https") {
return 301 https://$server_name$request_uri;
}
# Proxy requests to the Flask app running on port 5000
location ~ ^/(.*)$ {
proxy_pass http://python-flask:5000/$request_uri;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
它都是用下面的docker-compose挂载在Dockers中的。YML
version: '3.7'
services:
mongo:
image: mongo:latest
container_name: mongodb
restart: always
ports:
- "27017:27017"
volumes:
- ./data:/data/db
python-fastapi:
build:
context: .
dockerfile: DockerFile-fastapi
container_name: python-fastapi
restart: always
command: python3 fastapi_client.py
depends_on:
- mongo
python-flask:
build:
context: .
dockerfile: DockerFile-flask
container_name: python-flask
restart: always
command: python3 flask_app.py
depends_on:
- mongo
- python-fastapi
- nginx
nginx:
image: nginx:latest
container_name: nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./myapp.conf:/etc/nginx/conf.d/myapp.conf
- ./ssl:/etc/ssl
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
mongo-express:
image: mongo-express
container_name: mongo-express
restart: always
ports:
- "8081:8081"
environment:
ME_CONFIG_MONGODB_SERVER: mongodb
depends_on:
- mongo
这是我的第一个项目建设前端与API后端,所以除了问题,我有任何意见表示赞赏
我已经尝试了nginx配置中的许多更改,以及如何执行从登录到 Jmeter 板的重定向,但都不起作用。
通过debug,我已经检查到/dashboard的URL没有query_parameters,使auth_token为None。
我的想法是,nginx可能会阻止一些东西,但我实际上不知道。对于ngix配置,我尝试将proxy_server更改为proxy_pass http://python-flask:5000/$1$is_args$args,但没有成功。
编辑1:
我在这个问题中添加了相应的FastAPI实现。
# Create endpoint to get token after login
@app.post("/login")
async def login(user: str, password: str):
# Check that username is alphanumeric
if not user.isalnum():
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Username must be alphanumeric")
# Check that password is alphanumeric
if not password.isalnum():
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Password must be alphanumeric")
# Check that username is in the database
if not users_collection.find_one({"user": user}):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Username not found")
# Check that password is correct
if not users_collection.find_one({"user": user, "password": sha256(password.encode()).hexdigest()}):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Password is incorrect")
# Change with time.time()
token = sha256((user + password+str(time.time())).encode()).hexdigest()
# Save the session in mongodb
session_collection.insert_one({"token": token, "user": user})
return {"status": "ok", "message": "User logged in successfully", "token": token}
@app.get("/datasets")
async def datasets(auth_token: str):
if auth_token is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="You need to provide an auth_token")
session = session_collection.find_one({"token": auth_token})
# Must only get one user in session
if len(session["user"]) != 1:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="There is more than one user in the session")
for sess in session:
user_id = sess["user"]
datasets = datasets_collection.find({"user": user_id})
# Check length of datasets
if len(datasets) == 0:
return []
result = []
for dataset in datasets:
# Load pickle
ds = Dataset.from_mongo(dataset["dataset"])
result.append({"id": str(dataset["_id"]), "name": ds.name})
2条答案
按热度按时间vm0i2vca1#
我重写了你的
login
函数,做了一些修改和问题。这不是一个完整的解决方案,但应该让你走上正轨。login
函数依赖于用户名和密码的设置,所以不要使用request.form.get()
函数的默认值。如果缺少这些参数,则退出并返回特定错误。我不知道你的fast-api/login端点是如何配置的,但
params=
通常用于GET请求,而POST使用data=
/json=
。requests模块包含一个方便的错误捕获函数:
raise_for_status
。这将捕获任何“坏”响应,而不仅仅是状态!= 200。尤其是在调试中,不要掩盖实际错误是很重要的。如果得到错误x
,不要捕获它,而是记录错误y
--记录实际的错误,这样就可以知道到底出了什么问题。我也会在你的
dashboard()
函数中做类似的事情--不要掩盖实际的错误,打印出来。pu82cl6c2#
好吧,是我想太多了。
实际的问题是HTML中的请求没有传递查询参数。
我觉得自己好蠢