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)
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:
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:
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