nginx 无法在Flask中传递查询参数

ha5z0ras  于 2023-04-29  发布在  Nginx
关注(0)|答案(2)|浏览(147)

我的设置如下:

  • 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})
vm0i2vca

vm0i2vca1#

我重写了你的login函数,做了一些修改和问题。这不是一个完整的解决方案,但应该让你走上正轨。

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # don't wrap the entire thing into a try except block, makes debugging much harder if you don't know what
        # went wrong.
        #
        # don't use get() here - if the username and pass are missing, error. Defaults have no purpose here.
        user = request.form['user']
        password = request.form['password']

        # does fast api require a GET with params, or a POST with data?
        # if GET: requests.get(url, params=...)
        # if POST: requests.post(url, json=...)
        response = requests.post('http://python-fastapi:8000/login', json={'user': user, 'password': password})
        try:
            # error on any status errors, not just status != 200
            response.raise_for_status()
        except Exception:
            # just raise the original exception, or do something specific, but don't hide the explicit error
            raise

        # now you can try to access the response data
        response_data = response.json()
        # debugging: print(response_data)
        return redirect("/dashboard?auth_token="+response_data["token"])
    else:
        return render_template("login.html")

login函数依赖于用户名和密码的设置,所以不要使用request.form.get()函数的默认值。如果缺少这些参数,则退出并返回特定错误。
我不知道你的fast-api/login端点是如何配置的,但params=通常用于GET请求,而POST使用data=/json=
requests模块包含一个方便的错误捕获函数:raise_for_status。这将捕获任何“坏”响应,而不仅仅是状态!= 200。尤其是在调试中,不要掩盖实际错误是很重要的。如果得到错误x,不要捕获它,而是记录错误y--记录实际的错误,这样就可以知道到底出了什么问题。
我也会在你的dashboard()函数中做类似的事情--不要掩盖实际的错误,打印出来。

pu82cl6c

pu82cl6c2#

好吧,是我想太多了。
实际的问题是HTML中的请求没有传递查询参数。
我觉得自己好蠢

相关问题