3

So I'm creating a simple website in flask that allows two types of users. Admin and regular users. I have a class called "User" which has an attribute "isUser". I then have a route call "addMovie" which takes in a parameter "isUser" to check to see if the current user has the rights to add a movie. How do I check that? As of right now, I user that has that attribute set to "Yes" can still add a movie.

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(120))
    last_name = db.Column(db.String(120))
    email = db.Column(db.String(180), unique=True)
    password = db.Column(db.String(255))
    isUser = db.Column(db.String(10))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,backref=db.backref('users', lazy='dynamic'))

@app.route('/addMovie/<isUser>', methods=['GET', 'POST'])
@login_required
def addMovie(isUser):
    error = None
    if(isUser == "Yes"):
        error = "You must have Admin Privaledges to add a Movie/TV Show"
        return redirect(url_for('index'))
    else:
        return render_template('addMovie.html', error=error)
humbleCoder
  • 463
  • 1
  • 5
  • 18

3 Answers3

4

I assume you are using Flask-Login. Have you tried current_user?

Then you can check if the current logged in user is an admin or not. Finally call this method where admin functionalities is required.

from flask_login import current_user, login_required, LoginManager

@login_manager.user_loader
def load_user(id):
    return User.query.get(int(id))

def require_admin():
    if current_user.isUser:
        abort(403)

@app.errorhandler(403)
def error_access_forbidden(error):
    error_code = 403
    error_message = "Sorry, access denied or forbidden!"
    return render_template('4xx.html',
                           error_code = error_code,
                           error_message=error_message), 403

@app.route('/addMovie', methods=['GET', 'POST'])
@login_required
def addMovie():
    require_admin()
    error = None
    return render_template('addMovie.html', error=error)

The 4xx.html template may show the error code, error message and links for redirection. It is the right approach to handle the HTTP errors. You may implement other HTTP errors also.

Here is a sample error page that I have used one of my project:

error_404_demo

arshovon
  • 13,270
  • 9
  • 51
  • 69
  • It worked! Thanks! Now my question is, I have to redirect after the error to the index page and would like to flash a message. I've used a bootstrap theme so not sure how to have a white box pop up after the redirect. Or to have the 403 page show and then redirect after. That would work as well instead of flashing the messge – humbleCoder Nov 07 '17 at 13:47
  • Updated the answer to show HTTP 403 error page. Cheers! – arshovon Nov 07 '17 at 14:35
  • Wow! That's a beautiful error page! Thanks! I'll go look for a template! – humbleCoder Nov 07 '17 at 14:55
0

It will be good once you reconsidered your Model class like this...

class User(db.Model, UserMixin)
    is_admin = db.Column(db.Boolean(default=False))

Somehow you have to get the user object in your view function. If you're using Flask-login

from flask_login import current_user

if current_user.is_admin:
    return render_template('addMovie.html')
else:
    flash('You must have Admin Privaledges to add a Movie/TV Show')
    return redirect(url_for('index')

Or just get the object id

@app.route('/addMovie/<userid>', methods=['GET', 'POST'])
@login_required
def addMovie(userid):
    user = User.query.filter(id=userid).first()
Raja Simon
  • 10,126
  • 5
  • 43
  • 74
0

Here are some things to change to make it more pythonic:

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(120))
    last_name = db.Column(db.String(120))
    email = db.Column(db.String(180), unique=True)
    password = db.Column(db.String(255))
    is_admin = db.Column(db.Boolean(), default=False)
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,backref=db.backref('users', lazy='dynamic'))

@app.route('/addMovie/<user_id:int>', methods=['GET', 'POST'])
@admin_required
@login_required
def addMovie(user_id):
    user = db.session.query(User).get(user_id)
    return render_template('addMovie.html', user=user)   

def admin_required(f):
   def decorated(*args, **kwargs):
       if not g.user.is_admin:
         return redirect(url_for('index'))
   return f(*args, **kwargs)
return decorated

As you are using Flask's loging_required decorator, you can write your own admin_required and wrap your view with it. It should check if your user has permissions to add files and redirect him to index page if not. Also, I've changed your DB field to Boolean type because because it's more handy.

P.S. This snippet was not tested, it could contain some errors, but you've got the idea, right?

py_dude
  • 822
  • 5
  • 13