Answer a question

I am implementing a modified version of Duo Labs' py_webauthn demo in order to add physical authentication to my website. The demo is built in Flask, and uses the flask-login library in conjunction with an SQLAlchemy database to store user data.

What I would ideally like is for the Flask app to act as an Nginx authenticator, such that a logged-in user is able to access other proxy_pass'ed services on the server.

I had originally attempted to implement the reverse proxies in Flask, but the only working solution I have found requires the Twisted framework (as services like Shellinabox require constant requests being made), which needs a entirely separate WSGI application to be set up—an unnecessary middleman that is difficult to integrate.

My ideal result would be for a user to initially access the server and be proxy-pass'ed to the Flask authentication server, then would be able to access several other reverse-proxied services through Nginx. I am still open to a Python reverse proxy, but have found that Nginx best suits my needs.

How should I go about integrating Flask and Nginx?

(The app.py file for the demo library is available here. The Webauthn functionality is simply built on top of flask-login.)

Answers

I solved it! It is possible to use the builtin Nginx auth_request with Flask as an authenticator. Simply, if Flask returns a 200 upon being queried by Nginx, Nginx will then allow another page to be accessed. Alternatively, an error 401 can be returned by the authenticator to send the user to the Nginx 401 page (which, in my case, then redirects them to the login page).

To replicate, add an authenticator in Flask:

@app.route("/auth")
def nginx_auth():
    if current_user.is_authenticated:
        return "You are logged in! Sweet!"
    else:
        return 'Sorry, but unfortunately you\'re not logged in.', 401

Then, in Nginx, point an auth_request to the authenticator, and redirect 401 to the login page.

location /ssh {
   auth_request /auth;
   proxy_pass http://localhost:4200/;
}

location = /auth {
    internal;
    proxy_pass              https://localhost:8081/auth;
    proxy_pass_request_body off;
    proxy_set_header        Content-Length "";
    proxy_set_header        X-Original-URI $request_uri;
}

error_page 401 = @error401;
location @error401 {
    return 302 /login;
}

(Code modified from Nginx documentation.)

Logo

开发云社区提供前沿行业资讯和优质的学习知识,同时提供优质稳定、价格优惠的云主机、数据库、网络、云储存等云服务产品

更多推荐