【问题标题】:Flask session not persistedFlask 会话未持续
【发布时间】:2021-09-24 15:39:05
【问题描述】:

我正在开发一个使用 Flask 服务器端和 Angular 客户端的网络应用程序。 我需要在这样的应用程序中允许多用户登录,并且我想使用烧瓶会话对象来处理登录会话,但是会话在请求之间以及每次被销毁时都不会持久化。

我已经采用了一些解决方法(通过向请求和响应中添加特定的标头,flask_cors 已配置并正常工作)。

有什么建议吗?

谢谢:)

编辑:

这是我的 CORS 初始化

CORS(app, supports_credentials=True, resources=r'/*')

我用来填充会话对象的登录方法定义如下:

@app.route('/login', methods=['POST', 'GET'])
def login():
    print(request.headers)
    _json = request.json
    name = _json['username']
    password = _json['password']
    if name and password:
        m = hashlib.md5(password.encode('utf-8')).hexdigest()
        results = User.query.filter_by(username=name).first()
        if m == results.password:
            resp = jsonify("User logged in")
            resp.status_code = 200
            addRespHeaders(resp)
            session.permanent = True
            session['username'] = results.username
            session['role'] = results.role
            session.modified = True
            print(session['username'], session['role'])
            print(resp.headers)
            return resp
        else:
            resp = jsonify("Attention! Wrong Password")
            resp.status_code = 404
            addRespHeaders(resp)
            return resp
    else:
        resp = jsonify("Please enter the required fields")
        resp.status_code = 404
        addRespHeaders(resp)
        return resp

最后是 addRespHeaders(resp) 方法:

def addRespHeaders(resp):
    resp.headers.add('Access-Control-Allow-Headers', "Origin, Content-Type, X-Requested-With, Accept, x-auth")
    resp.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')

当我调用登录方法并尝试打印session['username']session['role'] 时,它会打印出正确的值,但如果使用另一种方法,例如:

@app.route('/user/getLoggedIn', methods=['GET'])
def getLoggedInUser():
    print('username' in session)
    logged_data = UserPersistence.query.all()[0].username
    logged_user = User.query.filter_by(username=logged_data).first()
    schema = UserSchema()
    resp = jsonify(schema.dump(logged_user))
    resp.status_code = 200
    addRespHeaders(resp)
    return resp

print('username' in session) 返回False

编辑2:

这是我的服务执行请求的样子:

    const httpOptions = {
    withCredentials: true,
    headers: new HttpHeaders({'Content-Type': 'application/json'})
};
@Injectable({providedIn: 'root'})
export class UserService{
    private userUrl = "http://192.168.0.88:5000";

    constructor(private http: HttpClient){ }

    /** GET users from server */
    getUsers(): Observable<User[]>{
        return this.http.get<User[]>(this.userUrl + '/users');
    }

    /** GET user by id. Will 404 if not found */
    getUser(id: number): Observable<any>{
        const url = `${this.userUrl}/user/${id}`;
        return this.http.get<User>(url);
    }

    getLoggedInUser(): Observable<User>{
        const url= `${this.userUrl}/user/getLoggedIn`;
        return this.http.get<User>(url);
    }
    /** POST: login user */
    login(username: string, password: string) {
        return this.http.post(this.userUrl + '/login', JSON.stringify({"username": username, "password": password}), httpOptions);
    }

    /** POST: logout logged in user */
    logout() {
        return this.http.post(this.userUrl + '/logout', httpOptions);
    }

    /** POST: add a new user to the server */
    addUser(user: User) {
        return this.http.post(this.userUrl + '/user/add', user, httpOptions);
    }

    /** PUT: update the user on the server */
    updateUser(user: User): Observable<any> {
        return this.http.put(this.userUrl + '/user/update', user, httpOptions);
    }

    /** PUT: update user password */
    updatePassword(user: PasswordReset): Observable<any> {
        return this.http.put(this.userUrl + '/user/changePassword', user, httpOptions);
    }

    /** DELETE: delete the user from the server */
    deleteUser(user: User | number) {
            const id = typeof user == 'number' ? user : user.id;
            const url = `${this.userUrl}/user/delete/${id}`;
            return this.http.delete(url, httpOptions);
    }
}

据我所知,withCredentials: true 应该包含凭据。

编辑3:

当我在本地主机中时,我设法在请求之间保持会话数据:

session_cookie = SecureCookieSessionInterface().get_signing_serializer(app)

@app.after_request
def after_request(response):
    origin = request.headers.get('Origin')
    if request.method == 'OPTIONS':
        response.headers.add('Access-Control-Allow-Credentials', 'true')
        response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
        response.headers.add('Access-Control-Allow-Headers', 'x-csrf-token')
        response.headers.add('Access-Control-Allow-Methods',
                             'GET, POST, OPTIONS, PUT, PATCH, DELETE')
        if origin:
            response.headers.add('Access-Control-Allow-Origin', origin)
    else:
        response.headers.add('Access-Control-Allow-Credentials', 'true')
        if origin:
            response.headers.add('Access-Control-Allow-Origin', origin)
    same_cookie = session_cookie.dumps(dict(session))
    response.headers.add("Set-Cookie", f"{same_cookie}; Secure; HttpOnly; SameSite=None; Path=/;")
    return response

现在的问题是,如果我尝试登录同一网络下的另一台 PC,所有请求都会被阻止,因为请求之间没有传递 cookie。 任何想法?谢谢

【问题讨论】:

    标签: angular multi-user flask-session


    【解决方案1】:

    您是否在初始化扩展时添加了 support_credentials=True 选项?

    更多来自文档:

    将 CORS 与 cookie 一起使用 默认情况下,Flask-CORS 不允许跨站点提交 cookie,因为它具有潜在的安全性 影响。如果您希望启用跨站点 cookie,您可能希望 添加某种 CSRF 保护以确保您和您的用户的安全。

    要允许跨域发送 cookie 或经过身份验证的请求, 只需将supports_credentials 选项设置为True。例如

    from flask import Flask, session from flask_cors import CORS
        
    app = Flask(__name__) 
    CORS(app, supports_credentials=True)
        
    @app.route("/")
        def helloWorld():   
            return "Hello, %s" % session['username']
    

    还要检查您的路由是否被列入 CORS 使用白名单或装饰器是否添加到路由中。

    One of the simplest configurations. Exposes all resources matching /api/* to
    CORS and allows the Content-Type header, which is necessary to POST JSON
    cross origin.
    
    CORS(app, resources=r'/api/*')
    
    
    @app.route("/")
    def helloWorld():
        """
            Since the path '/' does not match the regular expression r'/api/*',
            this route does not have CORS headers set.
        """
        return '''
    <html>
        <h1>Hello CORS!</h1>
        <h3> End to end editable example with jquery! </h3>
        <a class="jsbin-embed" href="http://jsbin.com/zazitas/embed?js,console">JS Bin on jsbin.com</a>
        <script src="//static.jsbin.com/js/embed.min.js?3.35.12"></script>
    
    </html>
    '''
    
    @app.route("/api/v1/users/")
    def list_users():
        """
            Since the path matches the regular expression r'/api/*', this resource
            automatically has CORS headers set. The expected result is as follows:
    
            $ curl --include -X GET http://127.0.0.1:5000/api/v1/users/ \
                --header Origin:www.examplesite.com
            HTTP/1.0 200 OK
            Access-Control-Allow-Headers: Content-Type
            Access-Control-Allow-Origin: *
            Content-Length: 21
            Content-Type: application/json
            Date: Sat, 09 Aug 2014 00:26:41 GMT
            Server: Werkzeug/0.9.4 Python/2.7.8
    
            {
                "success": true
            }
    
        """
        return jsonify(user="joe")
    

    另外,如果您正在使用蓝图,请记住将蓝图注册到 CORS。

    Flask-CORS 支持开箱即用的蓝图。只需传递一张蓝图 实例到 CORS 扩展,一切都会正常工作。

    api_v1 = Blueprint('API_v1', __name__)
    
    CORS(api_v1) # enable CORS on the API_v1 blue print
    

    所有示例均来自 Flask-Cors 文档。 Link to docs

    【讨论】:

    • 感谢您的回复!我编辑了我的问题,以包含更多实施细节。
    • 要明确仍在寻找解决方案。我发布了我的配置以表明即使建议的所有内容都已完成但仍然无法正常工作。
    • 您的 Fech() 看起来如何?您是否在请求中包含 credentials: 'include'?此外,将您的 Access-Control-Allow-Origin 设置为您的域,因为 CORS 扩展将其默认设置为通配符“*”。
    • 再次编辑了请求服务的问题。谢谢。
    • @NiccoloB 您是否在 Flask 中为您的域设置了 Access-Control-Allow-Origin?默认情况下,CORS 扩展会将其设置为通配符。如果您发送带有凭据的请求并且您的 Access-Control-Allow-Origin 设置为通配符,那么您的请求将类似于未经身份验证的请求。文档:注意:当响应凭证请求请求时,服务器必须在 Access-Control-Allow-Origin 标头的值中指定来源,而不是指定“*”通配符。 [@ 987654322@
    猜你喜欢
    • 2017-04-19
    • 2011-10-29
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 2011-07-18
    • 2019-10-10
    相关资源
    最近更新 更多