2016-07-25 43 views
2

我已經用flask_login編寫了Flask服務器。要登錄用戶,我使用login_user(user),並且我的網站上有一頁用@login_required加以保護。作爲一個客戶,我使用Python請求包,這是代碼:Flask服務器上的會話與Python請求包不起作用

import requests 
sess = requests.session() 
sess.post("http://page.on/my/site", data={"login" : "login", "password" : "password"}) 

一切皆與此認證OK,但後來我試圖訪問受保護的頁面:

r = sess.get("http://secure.page/on/the/site") 

而這個請求接收Unauthorized 。 設置身份驗證後,這是餅乾(現在我有我的本地主機上的服務器):

<RequestsCookieJar[<Cookie session=.eJwdzjkSwjAMAMC_uE4h2dbhfCZjHR5oE1Ix_B2Gbst9l2OdeT3K_jrv3MrxjLKX5tqBGbq7MfmPiYi8aA7RAG8haZJoDZ0HrlSG6Oa1-yCqsaJNJlSVAQToNXsAt8UiFQBIbIa3bmYiarYyiEaNsUJjmlLZyn3l-c_Uzxf_2C6a.Cnf0yA.xIUSIFgcvjqwszrbwCA_D2Rqa5k for localhost.local/>]> 

順便說一句,我也用這個:

login_manager.session_protection = "strong" 

如何解決此身份驗證問題?

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> 

UPD3: 我試圖用這樣的:

r = sess.get("http://secure.page/on/the/site", auth=("login", "password")) 

在我所看到的,在第一個用戶成功登錄服務器,但那麼無論如何服務器都會拋出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:

問題似乎是在login_user函數,它不會改變is_authenticatedTrue。我使用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) 

而且user_loader

@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 

標識打印正確,它的類型是str,查詢工作得很好,但我仍然得到Unauthenticated錯誤,並在最後的printuser.is_authenticated是假的。

UPD5:

其實user.is_authenticated只是login_user印刷後也顯示的是假的,即使我login_user後叫session.commit()

+0

根據文檔,當會話保護處於活動狀態時,每個請求都會爲用戶計算機生成一個標識符(基本上是IP地址和用戶代理的安全哈希)。因此,它不會看起來這是一個問題。你能發佈一個完整的[mcve]嗎? –

+0

@WayneWerner,查看我的更新回答 –

+0

您錯過了您的問題中的用戶加載器和您的用戶類,但很可能我的答案解決了您的問題。 –

回答

0

這似乎表現出你解釋行爲:

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',它的工作原理。我懷疑你的用戶加載器或用戶類有類似的設置。

正如我懷疑 - 你的用戶模型產生了一個不正確的is_authenticated。當然,它很可能是正好你告訴它。您只需修復已認證的位。請注意,如果您從用戶加載程序返回None,它將使用匿名用戶 - 您可以在is_authenticated方法中硬編碼True,除非您嘗試跨會話註銷用戶。

+1

'Flask-Login' *要求*你的用戶ID是一個文本類型(2.7中的'unicode'和3.x中的'str')。請參閱['get_id'](https://flask-login.readthedocs.io/en/latest/#your-user-class)文檔。好吧,我想嚴格來說,你可以重寫'get_id'來完成轉換,但'get_id'必須返回一個文本類型。 – jpmc26

+0

有用的知道 - 我懷疑'UserMixin'在'get_id'的幕後做了。 –

+0

@WayneWerner,我剛剛嘗試過,並添加了一些調試打印,並且問題非常不同 - 請參閱我的更新的答案 –

相關問題