使用flask-login with flask-admin

时间:2017-11-02 16:20:03

标签: python flask flask-login flask-admin

enter image description here

我正在查看开源应用https://github.com/AlvinCJin/deepfit-app/tree/master/app

这是使用flask-admin进行管理目的/在页面https://github.com/AlvinCJin/deepfit-app/blob/master/app/main/views.py上:

# admin management setup
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Post, db.session))
path = op.join(os.path.abspath(__file__ + "/../../"), 'static')  # need to get parent path of this code
admin.add_view(FileAdmin(path, '/static/', name='Static Files'))

这可以很好地生成一个有用的仪表板,但不安全。我已经安装了flask-login,我阅读了http://flask-admin.readthedocs.io/en/latest/introduction/#rolling-your-own部分,但我不清楚如何链接所讨论的课程:

class MicroBlogModelView(sqla.ModelView):

def is_accessible(self):
    return login.current_user.is_authenticated

def inaccessible_callback(self, name, **kwargs):
    # redirect to login page if user doesn't have access
    return redirect(url_for('login', next=request.url))

使用管理员路线。

用户表在models.py中定义为:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(64), unique=True)
    firstname = db.Column(db.String(100))
    lastname = db.Column(db.String(100))
    email = db.Column(db.String(120), index=True, unique=True)
    pwdhash = db.Column(db.String(54))
    phone = db.Column(db.Integer)
    address = db.Column(db.String(64))
    confirmed = db.Column(db.Boolean, default=False)

    role = db.Column(db.SmallInteger, default=ROLE_APPLICANT)
    comments = db.relationship('Comment', backref='author', lazy='dynamic')
    posts = db.relationship('Post', order_by="Post.timestamp", backref='author',
                            lazy='dynamic', cascade="all, delete, delete-orphan")
    about_me = db.Column(db.Text())
    last_seen = db.Column(db.DateTime, default=datetime.utcnow)
    member_since = db.Column(db.DateTime(), default=datetime.utcnow)
    portrait = db.Column(db.String(140))
    pref = db.relationship('Preference', uselist=False, backref='author')
    fav = db.relationship('Favourite', backref='user', lazy='dynamic')

    active = db.Column(db.Boolean, default=False)

    @staticmethod
    def make_unique_nickname(nickname):
        if User.query.filter_by(nickname=nickname).first() is None:
            return nickname
        version = 2
        while True:
            new_nickname = nickname + str(version)
            if User.query.filter_by(nickname=new_nickname).first() is None:
                break
            version += 1
        return new_nickname

    def __init__(self, nickname, firstname, lastname, email, password, role):
        self.nickname = nickname.title()
        self.firstname = firstname.title()
        self.lastname = lastname.title()
        self.email = email.lower()
        self.set_password(password)
        self.role = role

    def ping(self):
        self.last_seen = datetime.utcnow()
        db.session.add(self)

    def set_password(self, password):
        self.pwdhash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.pwdhash, password)

    def is_authenticated(self):
        return True

    def generate_confirmation_token(self, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'confirm': self.id})

    def confirm(self, token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except:
            return False
        if data.get('confirm') != self.id:
            return False
        self.confirmed = True
        db.confirmed = True
        db.session.add(self)
        return True

    def to_json(self):
        json_user = {
            'url': url_for('api.get_post', id=self.id, _external=True),
            'nickname': self.nickname,
            'member_since': self.member_since,
            'last_seen': self.last_seen,
            'posts': url_for('api.get_user_posts', id=self.id, _external=True),
            'post_count': self.posts.count(),
        }
        return json_user

    def generate_reset_token(self, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'reset': self.id})

    def generate_auth_token(self, expiration):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'id': self.id})

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except:
            return None
        return User.query.get(data['id'])

    def is_active(self):
        if self.active is True:
            return True
        else:
            return False

    def is_anonymous(self):
        return False

    def get_id(self):
        return unicode(self.id)

    def __repr__(self):
        return '<User %r>' % self.nickname

并且有一个is_authenticated方法,但是如何使用它来要求以特定用户身份登录?

我试过了:

class MyView(BaseView):
    @expose('/')
    def index(self):
        return self.render('admin/index.html')

    def is_accessible(self):
        return login.current_user.is_authenticated()

# admin management setup
admin.add_view(ModelView(User, db.session))
admin.add_view(ModelView(Post, db.session))
path = op.join(os.path.abspath(__file__ + "/../../"), 'static')  # need to get parent path of this code
admin.add_view(FileAdmin(path, '/static/', name='Static Files'))

基于:

https://flask-admin.readthedocs.io/en/v1.0.7/quickstart/

编辑:

因此,仅仅为了我的理解,你是继承ModelViews并增加了路由的能力?

我已将其更改为:

class MyView(ModelView):
    @expose('/')
    def index(self):
        return self.render('admin/index.html')

    def is_accessible(self):
        return login.current_user.is_authenticated()

# admin management setup
admin.add_view(MyView(User, db.session))
admin.add_view(MyView(Post, db.session))
path = op.join(os.path.abspath(__file__ + "/../../"), 'static')  # need to get parent path of this code
admin.add_view(FileAdmin(path, '/static/', name='Static Files'))

接近但我需要将其与烧瓶登录相结合 - 我得到了:

NameError: global name 'login' is not defined

EDIT2:

我已将其更改为:

class MyView(ModelView):
    @expose('/')
    @login_required
    def index(self):
        return self.render('admin/index.html')

删除is_accessible函数,因此未被覆盖,用户类已经内置了is_accessible函数。

这至少部分有效,但我想只允许访问用户定义为0的ROLE的管理员

1 个答案:

答案 0 :(得分:1)

你需要它像下面这样做

MyView

注册视图时需要使用include: /ClientApp类。如果您需要更多自定义,则需要在Flask登录使用的User对象中实现它们。在那里你可以创建支票组和你需要的任何其他东西