Redirect to previous URL after OAuth login is completed (flask-dance)

只谈情不闲聊 提交于 2019-12-11 06:34:48

问题


I am developing a Flask application that allows the user to login using OAuth (with Github as a provider), and the flask-dance library. For some reason I am not able to redirect, after a successful login, to the page from which I sent the user to the login page.

When the user tries to connect to, e.g., http://localhost:6675/examples/tutorial.first/, the user is redirected to the login page, showing in the URL the page we should redirect to (http://localhost:6675/login?next=%2Fexamples%2Ftutorial.first%2F)

The problem is that after I manage to login using Github, the application just goes back to the homepage.

I was checking Flask-dance documentation and the documentation for the make_github_blueprint() function mentions the parameters redirect_to and redirect_url, but when I try using them I cannot even complete the login step. Furthermore, it seems that it would work only with static addresses, while ideally I would like to jump back to the page I was before logging in. I also checked this SO question, but the problem there seems to be different.

Are there any examples on how to properly do redirection after logging in with Flask dance?

Here some code snippets which could be relevant. In the init.py file:

bp_github = make_github_blueprint(
    client_id="...",
    client_secret="...",
)
login_manager = LoginManager()
login_manager.login_github_view = 'github.login'
login_manager.login_view = 'login'

And in the app.py file:

@app.route("/login", methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return flask.redirect(flask.url_for('/'))
    return flask.render_template('login.html')

@app.route("/logout")
@login_required
def logout():
    logout_user()
    flask.flash("You have logged out")
    return flask.redirect(flask.url_for("login"))

@oauth_authorized.connect_via(bp_github)
def logged_in(blueprint, token):
    """
    create/login local user on successful OAuth login with github
    :param blueprint:
    :param token:
    :return:
    """
    if not token:
        flask.flash("Failed to log in.", category="error")
        return False

    session = blueprint.session

    resp = session.get("/user")

    if not resp.ok:
        msg = "Failed to fetch user info."
        flask.flash(msg, category="error")
        return False

    user_id = str(info["id"])

    # Find this OAuth token in the database, or create it
    query = OAuth.query.filter_by(
        provider=blueprint.name,
        provider_user_id=user_id,
    )
    try:
        oauth = query.one()
    except NoResultFound:
        oauth = OAuth(
            provider=blueprint.name,
            provider_user_id=user_id,
            token=token,
        )

    if oauth.user:
        login_user(oauth.user)
        flask.flash("Successfully signed in.")

    else:
        # Create a new local user account for this user
        name = info['login']

        user = User(
            email=info["email"],
            name=name,
            provider=provider
        )
        # Associate the new local user account with the OAuth token
        oauth.user = user
        # Save and commit our database models
        db.session.add_all([user, oauth])
        db.session.commit()
        # Log in the new local user account
        login_user(user)
        flask.flash("Successfully signed in.")

    # Disable Flask-Dance's default behavior for saving the OAuth token
    return False

回答1:


I had the same problem and I think what you are trying to accomplish is not really possible by passing the next url as arguments. If you want to use the "next" request argument, you need to go in the developer console and add every possible redirect url that the user could have (which is not really a good solution for you). What I would suggest if you really want to make it dynamic is to pass the next url in the state parameter (see this for more details about the state object. According to this documentation:

You can use this parameter for several purposes, such as directing the user to the correct resource in your application, sending nonces, and mitigating cross-site request forgery.

Unfortunately, Flask-Dance does not support this out the box so you will need to dig a little bit in the library. I would suggest taking a look at the OAuth2ConsumerBlueprint object and try to implement a custom blueprint that would work for you.

In my case, I wanted to redirect the user to another application on my domain after the successful OAuth authentication. What I do with Flask-Dance is pass the other application url in the "next" parameter like so

http://api.mycompany.com/auth/google?next=https://myotherapp.mycompany.com

and I make sure to add the complete authorized url in the google console like such:

http://api.mycompany.com/auth/google/authorized?next=https%3A%2F%2Fmyotherapp.mycompany.com

With this technique you can redirect to the desired urls without using the redirect_to parameter (which can only take one value) in flask-dance




回答2:


My answer might be a bit late since you have mentioned that your company decided to allow users only registered on your domain. However, I am still posting this for other users who might have this question.

To solve this problem, you will need to have a basic login page that first stores the next_url that the user should be redirected to once the login is complete via your domain login or the OAuth login. Flask adds the next parameter in the URL when you use @login_required on the URL which should be allowed only for logged in users. You need to add session['next_url'] = request.args.get('next') in your login route to capture the next parameter and store it in the session as next_url. Now, in case of the OAuth login, once the user is redirected to the default redirect_url after successful login, you will read the next_url value from the session and redirect the user to that URL if it exists or else render the default page (usually the home page.)

I am assuming 2 things, 1. that your default URL after OAuth login is successful is /home. This is set using the redirect_url of the make_provider_blueprint function in your case it is make_github_blueprint. Secondly, I am assuming your login page is the landing page for the user when they are not logged and it displays the GitHub login button which starts the OAuth login procedure. You might have to modify this flow slightly for your case to capture the next_url accordingly.

I have shared the minimal code required to handle this situation below. Note that I pop the next_url value from the session before redirecting. This is so that in case the user tries to access the home page after the login, they should not be always redirected to the next_url if it exists in the session.

bp_github = make_github_blueprint(
    client_id="...",
    client_secret="...",
    redirect_url="/home"
)

@app.route("/login", methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return flask.redirect(flask.url_for('/'))
    session['next_url'] = request.args.get('next')
    return flask.render_template('login.html')

@auth.route("/")
@auth.route("/home")
@login_required
def home():
    if session.get('next_url'):
        next_url = session.get('next_url')
        session.pop('next_url', None)
        return redirect(next_url)
    return render_template('home.html')

Let me know if this was helpful or you need any other information. I will be happy to help.



来源:https://stackoverflow.com/questions/51401455/redirect-to-previous-url-after-oauth-login-is-completed-flask-dance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!