首页 > 解决方案 > How can i control multiple logins(like admin login and normal login) with flask login_required decorator

问题描述

I want to control multiple logins with login_required decorator in flask. In my project i want only admin to be able to add articles, and registered users to be able to comment them. I hid the logout page and profile page from unregistered users but i cant hide the add article page from registered users how can i solve this problem?

from flask import Flask,render_template,flash,redirect,url_for,session,logging,request
from flask_mysqldb import MySQL
from wtforms import Form,StringField,TextAreaField,PasswordField,validators
import email_validator
from passlib.hash import pbkdf2_sha256
from functools import wraps

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if "logged_in" in session:
            return f(*args, **kwargs)
        else:
            flash("Bu Sayfayı Görüntülemek İçin Giriş Yapmalısınız","danger")
            return redirect(location=(url_for("login")))
    return decorated_function

@app.before_request
def before_request_func():
    

class RegisterForm(Form):
    name = StringField("İsim Soyisim", validators=[validators.Length(min=4,message="En az 4 karakter uzunluğunda bir girdi giriniz"),validators.DataRequired()])
    user_name = StringField("Kullanıcı Adı", validators=[validators.Length(min=4,message="En az 4 karakter uzunluğunda bir girdi giriniz"),validators.DataRequired()])
    email = StringField("Email Adresi", validators=[validators.Length(min=4,message="En az 4 karakter uzunluğunda bir girdi giriniz"),validators.DataRequired(),validators.Email(message="Lütfen Geçerli Bir Email Giriniz")])
    password = PasswordField("Şifre",validators=[validators.DataRequired("Lütfen Bir Parola Belirleyin"),validators.EqualTo(fieldname="confirm",message="Parolanız Uyuşmuyor")])
    confirm = PasswordField("Parola Doğrula")

class LoginForm(Form):
    email = StringField("Email Adresi",validators=[validators.DataRequired(message="Lütfen Emailinizi Giriniz")])
    password = PasswordField("Şifre",validators=[validators.DataRequired(message="Lütfen Şifrenizi Giriniz")])

app =  Flask(__name__)

mysql = MySQL(app)

app.secret_key = "furkanselek"
app.config["MYSQL_DATABASE_HOST"] = "localhost"
app.config["MYSQL_DATABASE_USER"] = "root"
app.config["MYSQL_DATABASE_PASSWORD"] = ""
app.config["MYSQL_DB"] = "furkanselek"
app.config['MYSQL_CURSORCLASS'] = "DictCursor"
app.config["MYSQL_DATABASE_PORT"] = "3306"


@app.route("/")
def index():
    return render_template("index.html")
@app.route("/about")
def about():
    return render_template("about.html")
@app.route("/register",methods=["GET","POST"])
def register():
    form = RegisterForm(request.form)
    if request.method == "POST" and form.validate():
        name = form.name.data
        username = form.user_name.data
        email = form.email.data
        password = pbkdf2_sha256.encrypt(form.password.data)
        cursor = mysql.connection.cursor()
        sorgu = ("Insert into users (name,email,username,password) VALUES(%s,%s,%s,%s)")
        cursor.execute(sorgu,(name,email,username,password))
        mysql.connection.commit()
        cursor.close()
        flash("Başarıyla Kayıt Oldunuz",category="warning")
        return redirect(location =(url_for("login")))
    else:
        return render_template("register.html",form= form)
@app.route("/login",methods=["GET","POST"])
def login():
    form = LoginForm(request.form)
    if request.method == "POST" and form.validate():
        email = form.email.data
        password_entered = form.password.data
        cursor = mysql.connection.cursor()
        query = ("SELECT * FROM users WHERE email = %s")
        result = cursor.execute(query,(email,))
        if result > 0:
            data = cursor.fetchone()
            username = data["username"]
            password = data["password"]
            if pbkdf2_sha256.verify(password_entered,password):
                flash("Başarıyla Giriş Yaptınız",category="warning")
                if username == "maxkonrad":
                    session["admin"] = True
                    session["logged_in"] = True
                    session["username"] = username
                    return redirect(location=(url_for("index")))
                else:
                    session["logged_in"] = True
                    session["username"] = username 
                    return redirect(location=(url_for("index")))
            else:
                flash("Parolanızı Yanlış Girdiniz",category="warning")
                return redirect(location=(url_for("login")))
        else:
            flash("Bu Email ile Kayıt Olmuş Bir Kullanıcı Yok")
            return redirect(location=(url_for("login")))
    else:
        return render_template("login.html",form= form)
@app.route("/logout")
@login_required
def logout():
    session.clear()
    return redirect(location=(url_for("index")))
@app.route("/addarticle",methods=["GET","POST"])
def addarticle():
    return render_template("addarticle.html")

@app.route("/profile")
@login_required
def profile():
    return render_template("profile.html")
if __name__ == "__main__":
    app.run(debug=True)

标签: pythonflasklogin-required

解决方案


In Role based authorization in flask-login the accepted answer appears to be using Flask-Principal However, you can also do this with Flask-User which seems to be more actively maintained. There's a superb basic-app for Flask-User which spins up with a single app.py file. The app provides two roles (admin and manager) as well as three routes that demo the authentication and basic role based authorization that is provided by Flask-User. They are pretty self-explanatory:

# The Home page is accessible to anyone
@app.route('/')
def home_page():

# The Members page is only accessible to authenticated users
@app.route('/members')
@login_required    # Use of @login_required decorator
def member_page():

# The Admin page requires an 'Admin' role.
@app.route('/admin')
@roles_required('Admin')    # Use of @roles_required decorator
def admin_page():

Flask-User can also be used to do more complex forms of authorization. You can make more roles and then authorize routes to only allow users access if they have that role and/or another role. For example, you could make an admin, a teacher, and a student role. And then vary accessibility based on those roles and/or combination of roles. Here's a couple of examples:

@admin_blueprint.route('/admin/teacher_or_admin')
@roles_required(['admin', 'teacher'])  # requires admin OR teacher role
def admin_teacher_or_admin():
    return "You have the right roles to access this page - it requires admin OR teacher roles"

@admin_blueprint.route('/admin/teacher_and_admin')
@roles_required('admin','teacher')  # requires admin AND teacher roles
def admin_teacher_and_admin():
    return "You have the right roles to access this view"

@admin_blueprint.route('/admin/student')
@roles_required('student')  
def admin_student():
    return "You have the right roles to access this page - requires student role"

Although it's not a single file like the basic-user app above, this repo demonstrates these more advanced flask-user authorization capabilities: https://github.com/lfernandez55/3200_Final_Project_Challenge


推荐阅读