我在用户通过OAuth登录的网站上工作,而不是基于密码的系统。
因此,Flask-Security的默认登录页面实际上并不适用于我的用例,因为我需要/login
端点来进行OAuth设置。我能够通过更改/login
设置选项,使我的SECURITY_LOGIN_URL
路由没有被Flask-Security覆盖。
这一切正常,OAuth登录页面显示并返回所需的所有信息。
问题出现了,因为我也尝试使用@login_required
装饰器。
如果用户未登录,则/login
装饰器会重定向到我的@login_required
页面,而不是重定向到Flask-Security的页面。
显然,配置端点在这种情况下没有帮助。
是否可以强制Flask-Security使用我的登录路由(OAuth)而不是其页面?
这是一些示例代码,显示了我正在讨论的Flask-Security覆盖定义的路线:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, request
from flask_security import (Security, SQLAlchemyUserDatastore,
UserMixin, RoleMixin, login_required,
login_user, logout_user, current_user)
from passlib.context import CryptContext
import os
class Config:
basedir = os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
SQLALCHEMY_TRACK_MODIFICATIONS = False
DEBUG = True
PORT = 8000
HOST = "0.0.0.0"
SECRET_KEY = "foobar123"
config = Config()
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(config)
db = SQLAlchemy(app)
lm = LoginManager()
lm.init_app(app)
lm.login_view = "login"
roles_users = db.Table('roles_users',
db.Column('user_id',
db.Integer(),
db.ForeignKey('user.id')),
db.Column('role_id',
db.Integer(),
db.ForeignKey('role.id'))
)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
provider_id = db.Column(db.String(64), index=True, unique=True)
@property
def is_authenticated(self):
return True
@property
def is_active(self):
return True
@property
def is_anonymous(self):
return True
def get_id(self):
return str(self.id)
def hash_password(self, password):
self.hashed_password = pwd_context.encrypt(password)
def verify_password(self, password):
return pwd_context.verify(password, self.hashed_password)
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
pwd_context = CryptContext(
schemes=["bcrypt", "pbkdf2_sha256", "des_crypt"],
default="bcrypt",
all__vary_rounds=0.1
)
@lm.user_loader
def load_user(id):
return User.query.get(int(id))
@app.route("/")
@app.route("/index")
@login_required
def index():
"""Handles calls to / and /index, return the panel"""
return render_template("index.html")
@app.route("/login")
def login():
"""Would include a bunch of OAuth stuff, not required for this example
If you try going to this endpoint, you'll get the Flask-Security /login
instead."""
return render_template("login.html")
app.run(debug=True)
答案 0 :(得分:2)
有趣的是,我今天遇到了一个非常类似的问题。 如果我设法以某种方式解决它,我会考虑优雅的SO答案,我会更新这个。与此同时,我对解决问题的策略的看法是:
@login_required
装饰器以将您重定向到正确的位置。如果重定向是您遇到的唯一问题,可能最快。@login_required
。 Flask-OAuthlib是一个有用的誓言库,documents show you how to protect a resource使用`@ oauth.require_oauth'装饰器。 Flask-Stormpath是一个商业解决方案,我不太熟悉它是否涵盖了这个特定的理由,因此我不建议将其作为一种可能的方法。但是for background reading他们对与Flask相关的认证大黄蜂巢有一个有用的概述。
答案 1 :(得分:0)
您可能希望覆盖原始Flask-Security的登录视图。像这样:
id: 3
就是这样。如果您想使用Flask-Security的原始HTML模板,您还需要覆盖它(请参阅Flask-Security's documentation)。在那里,您只需放置自己的视图而不是旧视图:
my_blueprint = Blueprint('my_blueprint', __name__)
@bp.route('/login', methods=['GET', 'POST'])
@anonymous_user_required
def my_login_view():
# Do whatever you want to do here. Try to find inspiration in the original code
app = Flask(__name__)
app.register_blueprint(my_blueprint)
# You will need to define User and Role classes, see Flask-Security's documentation
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)