简体   繁体   English

使用flask-googlelogin与gunicorn和nginx导致400 Bad Request

[英]Using flask-googlelogin with gunicorn and nginx causing 400 Bad Request

Update: It seems to work when I configure my nginx server to allow http and set the Redirect URI for Google OAuth to use http (not https). 更新:当我配置我的nginx服务器以允许http并将Google OAuth的重定向URI设置为使用http(而非https)时,它似乎有效。 I'd really prefer to use HTTPS, though, so any thoughts are appreciated. 不过,我真的更喜欢使用HTTPS,所以任何想法都会受到赞赏。


I'm trying to use the flask-googlelogin plugin to authorize users to my web-app. 我正在尝试使用flask-googlelogin插件来授权用户访问我的网络应用程序。 Things are working fine when running the debug server and connecting to it directly, but when I run my app behind nginx acting as a reverse proxy (either to the debug server or to my app running inside gunicorn), I get 400 Bad Request responses on my login callback that say "The browser (or proxy) sent a request that this server could not understand". 运行调试服务器并直接连接到它时,工作正常,但当我在nginx后面运行我的应用程序作为反向代理(无论是调试服务器还是我在gunicorn内运行的应用程序),我得到400 Bad Request响应我的登录回调说“浏览器(或代理)发送了此服务器无法理解的请求”。

The gunicorn logs (when running with gunicorn) don't show anything interesting. gunicorn日志(与gunicorn一起运行时)没有表现出任何有趣的东西。 The nginx logs (on info level) show the 400 being returned: nginx日志(在info级别)显示返回的400:

» tail -f /var/log/nginx/*

==> /var/log/nginx/access.log <==
76.164.174.115 - - [21/May/2014:13:07:46 -0500] "GET /login HTTP/1.1" 200 1368 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36"
76.164.174.115 - - [21/May/2014:13:07:49 -0500] "GET /oauth2callback?state=[redacted]&code=[redacted] HTTP/1.1" 400 192 "https://redacted.com/login" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36"

This 400 seems to be coming from flask. 这400似乎来自于烧瓶。 If I run my app from the console (not inside gunicorn) I see the following: 如果我从控制台运行我的应用程序(不在gunicorn内),我会看到以下内容:

» python automation.py
 * Running on http://127.0.0.1:8000/
 * Restarting with reloader
127.0.0.1 - - [21/May/2014 12:12:17] "GET /login HTTP/1.0" 200 -
127.0.0.1 - - [21/May/2014 12:12:20] "GET /oauth2callback?state=[redacted]&code=[redacted] HTTP/1.0" 400 -

So the GET is being proxied to the application, but flask doesn't like it for some reason. 所以GET代理了应用程序,但是由于某些原因,烧瓶不喜欢它。 Here are the relevant parts of my application: 以下是我的申请的相关部分:

from flask import Flask, request, render_template, redirect, url_for, flash, session
from flask_login import current_user, login_required, login_user, logout_user, UserMixin, LoginManager
from flask_googlelogin import GoogleLogin
from werkzeug.contrib.fixers import ProxyFix
import json

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
app.secret_key = "redacted"
app.config.update(
    GOOGLE_LOGIN_CLIENT_ID='redacted',
    GOOGLE_LOGIN_CLIENT_SECRET='redacted',
    GOOGLE_LOGIN_REDIRECT_URI='https://redacted.com/oauth2callback',
)

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
login_manager.login_message = u"Please log in to access this page."
login_manager.login_message_category = u"danger"
googlelogin = GoogleLogin(app, login_manager)

class User(UserMixin):
    def __init__(self, userinfo):
        self.name = userinfo['name']
        self.id = userinfo['id']
        self.picture = userinfo.get('picture')

users = {
    "redacted1" : None,
    "redacted2" : None,
}

@googlelogin.user_loader
@login_manager.user_loader
def load_user(userid):
    return users.get(userid)

@app.route("/login", methods=['GET', 'POST'])
def login():
    return render_template('login.html', login_url=googlelogin.login_url())

@app.route('/oauth2callback')
@googlelogin.oauth2callback
def oauth2callback(token, userinfo, **params):
    if userinfo['id'] in users:
        user = users[userinfo['id']] = User(userinfo)
        login_user(user)
        session['token'] = json.dumps(token)
        flash("Logged in", "success")
        return redirect(params.get('next', url_for('automation')))
    else:
        flash("That google user is not authorized.", "danger")
        return redirect(url_for('login'))

@app.route("/automation", methods=['GET'])
@login_required
def automation():
    return render_template('automation.html')

@app.route("/logoff")
@login_required
def logoff():
    logout_user()
    session.clear()
    flash("logged out", "info")
    return redirect(url_for('login'))

if __name__ == "__main__":
    app.config.update( GOOGLE_LOGIN_REDIRECT_URI='http://localhost:5000/oauth2callback' )
    app.run(debug=True)

The usual reason for 400 Bad Request errors out of Flask seems to be an uncaught exception in a view function, but I've tried reducing my entire oauth2callback to nothing but a print and a pass and still fails and I don't see the print output. Flask中出现400 Bad Request错误的常见原因似乎是视图函数中未被捕获的异常,但我已经尝试将我的整个oauth2callback减少到只有printpass但仍然失败并且我没有看到打印输出。

Here is the relevant part of my nginx config: 这是我的nginx配置的相关部分:

server {
    listen 443;
    server_name redacted.com www.redacted.com;

    root /usr/share/nginx/www;
    index index.html index.htm;

    ssl on;
    ssl_certificate /etc/ssl/certs/ssl-bundle.pem;
    ssl_certificate_key /etc/ssl/private/myserver.key;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    ssl_prefer_server_ciphers on;

    location / {
            try_files $uri $uri/ @proxy_to_app;
    }

    location @proxy_to_app {
            proxy_pass http://127.0.0.1:8000;
            proxy_redirect off;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Thanks in advance. 提前致谢。

I had the same problem using uwsgi. 我使用uwsgi时遇到了同样的问题。

I was able to fix it by adding the following line to my /etc/nginx/uwsgi_params . 我能够通过在/etc/nginx/uwsgi_params添加以下行来修复它。

uwsgi_param  UWSGI_SCHEME       $server_protocol;

I also added to my app.config 我还添加到了我的app.config中

app.config['GOOGLE_LOGIN_REDIRECT_SCHEME'] = "https"

Best of luck. 祝你好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM