Flask服务器上Python请求包不工作的会话

Flask服务器上Python请求包不工作的会话,python,authentication,flask,flask-sqlalchemy,flask-login,Python,Authentication,Flask,Flask Sqlalchemy,Flask Login,我已经用Flask\u登录名编写了Flask服务器。要登录用户,我使用login\u user(user),我的站点的一个页面由@login\u required保护。作为客户机,我使用Python请求包,代码如下: import requests sess = requests.session() sess.post("http://page.on/my/site", data={"login" : "login", "password" : "password"}) 此身份验证一切正常,但

我已经用Flask\u登录名编写了Flask服务器。要登录用户,我使用
login\u user(user)
,我的站点的一个页面由
@login\u required
保护。作为客户机,我使用Python请求包,代码如下:

import requests
sess = requests.session()
sess.post("http://page.on/my/site", data={"login" : "login", "password" : "password"})
此身份验证一切正常,但我尝试访问安全页面:

r = sess.get("http://secure.page/on/the/site")
并且此请求接收未经授权的
。 这是身份验证后设置的cookies(目前我的服务器位于localhost上):

如何解决此身份验证问题

UPD:

这是服务器登录代码:

@api.route("/login/", methods=["POST"])
def handle_login_request():
    login, password = str(request.form['login']).lower(), str(request.form['password'])
    # Get and check user here
    login_user(user)
    # update user and get user_data
    return jsonify(user_data)
安全路线:

@api.route("/users_of_group/")
@login_required
def get_user_of_users_group():
    # code here never executes because of @login_required
api
是烧瓶蓝图的名称

UPD2:

这是sess返回的页面内容。get:

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
 <title>401 Unauthorized</title>
 <h1>Unauthorized</h1>
 <p>The server could not verify that you are authorized to access the URL requested.  You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.</p>
在服务器上,我可以看到,最初用户成功登录,但服务器仍然抛出401

import requests
sess = requests.session()
login = sess.post("http://page.on/my/site", data={"login" : "login", "password" : "password"})
r = sess.get("http://secure.page/on/the/site", cookies=login.cookies)
还可以登录用户,然后抛出401

UPD4:

问题似乎出现在登录用户功能中,它不会将
is\u authenticated
更改为
True
。我使用SQLAlchemy,这是我的用户类:

class User(db.Model):
    user_id = db.Column(db.Integer, primary_key=True)
    # Many required for my app fields
    is_active = db.Column(db.Boolean, default=False)
    is_authenticated = db.Column(db.Boolean, default=False)
    is_anonymous = db.Column(db.Boolean, default=False)
    is_online = db.Column(db.Boolean, default=False)

    # Init function 

    def get_id(self):
        return str(self.user_id)
用户加载程序

@login_manager.user_loader
def load_user(user_id):
    print(user_id, type(user_id))
    user = User.query.filter_by(user_id=int(user_id)).first()
    print(user.login, user.is_authenticated)
    return user
Id打印正确,其类型为
str
,查询工作正常,但我仍然得到
未经验证的
错误,并且在上一次
打印中
用户。是否经过验证
为False

UPD5:


实际上,在
login\u user
之后打印
user.is\u authenticated
也会显示False,即使我在
login\u user

之后调用了
session.commit()
这似乎显示了您所解释的行为:

from flask import Flask, request
from flask_login import LoginManager, UserMixin, login_user, login_required, \
                        current_user

app = Flask(__name__)
app.secret_key = 'This is totally a secret'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.session_protection = 'strong'


class User(UserMixin):
    id = 42

    @property
    def is_authenticated(self):
        print('{!r}'.format(self.id))
        return self.id == 42


@login_manager.user_loader
def get_user(id):
    user = User()
    user.id = id
    return user


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user = User()
        user.id = request.form.get('id', 42)
        login_user(user)
    else:
        user = current_user
    return 'Okay, logged in with id {}'.format(user.id)


@app.route('/')
@login_required
def main():
    return 'Hey cool - your id {}'.format(current_user.id)



if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001, debug=True)
这里需要注意的是ID是
'42'
,而不是
42
。显然,从会话中解码id不够聪明,无法知道您的id不是字符串。通过将我的函数更改为
return str(self.id)='42'
,它可以工作。我怀疑您的用户加载器或用户类中有类似的设置


正如我所怀疑的那样,您的用户模型产生了一个错误的
是否经过身份验证
。当然,它很可能完全按照你说的做。您只需修复经过身份验证的位。请注意,如果您从用户加载程序返回
None
,它将使用匿名用户-您可以在
is authenticated
方法中硬编码
True
,除非您试图跨会话注销用户。

根据文档,当会话保护处于活动状态时,每个请求,它生成用户计算机的标识符(基本上是IP地址和用户代理的安全散列)。所以这看起来根本不是问题。你能发布一个完整的吗?@WayneWerner,查看我的更新答案你的问题中缺少了用户加载程序和用户类,但我的答案很可能解决了你的问题。
Flask登录
要求你的用户ID为文本类型(
unicode
在2.7和
str
在3.x中)。请参阅文档。嗯,我想严格地说,你可以重写
get\u id
来进行转换,但是
get\u id
必须返回一个文本类型。知道这一点很有用-我怀疑
UserMixin
在幕后为
get\u id
@WayneWerner做了这件事,我刚刚尝试了这个并添加了一些调试打印,问题是完全不同的-看我更新的答案实际上正是这个问题-你的
经过身份验证
值返回False。我会在我的回答中添加一些细节。我已经更新了我的回答,如果你想要一些具体的东西,你必须提供你的登录方法的其余部分。
class User(db.Model):
    user_id = db.Column(db.Integer, primary_key=True)
    # Many required for my app fields
    is_active = db.Column(db.Boolean, default=False)
    is_authenticated = db.Column(db.Boolean, default=False)
    is_anonymous = db.Column(db.Boolean, default=False)
    is_online = db.Column(db.Boolean, default=False)

    # Init function 

    def get_id(self):
        return str(self.user_id)
@login_manager.user_loader
def load_user(user_id):
    print(user_id, type(user_id))
    user = User.query.filter_by(user_id=int(user_id)).first()
    print(user.login, user.is_authenticated)
    return user
from flask import Flask, request
from flask_login import LoginManager, UserMixin, login_user, login_required, \
                        current_user

app = Flask(__name__)
app.secret_key = 'This is totally a secret'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.session_protection = 'strong'


class User(UserMixin):
    id = 42

    @property
    def is_authenticated(self):
        print('{!r}'.format(self.id))
        return self.id == 42


@login_manager.user_loader
def get_user(id):
    user = User()
    user.id = id
    return user


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user = User()
        user.id = request.form.get('id', 42)
        login_user(user)
    else:
        user = current_user
    return 'Okay, logged in with id {}'.format(user.id)


@app.route('/')
@login_required
def main():
    return 'Hey cool - your id {}'.format(current_user.id)



if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001, debug=True)