过去一周这一直压垮我的头骨。我希望能够根据用户的角色限制 Flask 应用程序中对 Dash 应用程序的访问。我使用 flask mega 教程 作为创建此应用程序的指南,并使用 this 指南 嵌入破折号应用程序。我在 index.html 模板中创建了条件语句,以控制用户登录后看到的与其角色相关的链接:
{% extends "base.html" %}
{% block app_content %}
<h1>Hi, {{ current_user.username }}!</h1>
<h2>
My Dashboards
</h2>
{% if current_user.role == 'Department Head' %}
<a href="/laborcosts" class="dash-link" target="_blank">
<span>Labor Costs</span>
</a>
<br>
<a href="/dtidpriority" class="dash-link" target="_blank">
<span>DTID Priority</span>
</a>
<br>
<a href="/auditreturnreport" class="dash-link" target="_blank">
<span>Audit Return Report</span>
</a>
<br>
<a href="/automationerrorreport" class="dash-link" target="_blank">
<span>Automation Error Report</span>
</a>
<br>
<a href="/clientvolume" class="dash-link" target="_blank">
<span>Client Volume</span>
</a>
<br>
<a href="/outofscope" class="dash-link" target="_blank">
<span>Out Of Scope</span>
</a>
<br>
<a href="/teamlevelpoints" class="dash-link" target="_blank">
<span>Team Level Points</span>
</a>
<br>
<a href="/userlevelpoints" class="dash-link" target="_blank">
<span>User Level Points</span>
</a>
<br>
<a href="/usererrorreport" class="dash-link" target="_blank">
<span>User Error Report</span>
</a>
{% endif %}
{% if current_user.role == 'Team Lead' %}
<a href="/auditreturnreport" class="dash-link" target="_blank">
<span>Audit Return Report</span>
</a>
<br>
<a href="/automationerrorreport" class="dash-link" target="_blank">
<span>Automation Error Report</span>
</a>
<br>
<a href="/clientvolume" class="dash-link" target="_blank">
<span>Client Volume</span>
</a>
<br>
<a href="/outofscope" class="dash-link" target="_blank">
<span>Out Of Scope</span>
</a>
<br>
<a href="/teamlevelpoints" class="dash-link" target="_blank">
<span>Team Level Points</span>
</a>
<br>
<a href="/userlevelpoints" class="dash-link" target="_blank">
<span>User Level Points</span>
</a>
<br>
<a href="/usererrorreport" class="dash-link" target="_blank">
<span>User Error Report</span>
</a>
{% endif %}
</div>
{% endblock %}
这是解决该问题的一种方法。但是,如果用户只需在地址栏中输入任何嵌入式仪表板应用程序的路径,则无论其角色如何,他们都可以访问仪表板。这就是我试图限制的。我研究过 Flask-Authorize、Flask-Principal 和 Flask-RBAC,但发现几乎所有它们的文档充其量都是神秘的。至少,我无法理解在我的特定实例中实施这些解决方案的正确方法。任何帮助将不胜感激!
模型.py
import jwt
from time import time
from flask import current_app
from landing_page_pkg import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from landing_page_pkg import login
from flask_security import RoleMixin
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)
password_hash = db.Column(db.String(128))
role = db.Column(db.String(64))
pin = db.Column(db.Integer)
def __repr__(self):
return f'<User {self.username}>'
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
current_app.config['SECRET_KEY'], algorithm='HS256')
@staticmethod
def verify_reset_password_token(token):
try:
id = jwt.decode(token, current_app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
@login.user_loader
def load_user(id):
return User.query.get(int(id))
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, RadioField, IntegerField
from wtforms.validators import DataRequired, ValidationError,Email,EqualTo
from landing_page_pkg.models import User
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me')
submit = SubmitField('Sign In')
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
password2 = PasswordField(
'Repeat Password', validators=[DataRequired(), EqualTo('password')])
### NOTICE: To get the label to show for the "Role" field using wtf.quickform
### you must edit flask-bootstrap/templates/wtf.html and add {{field.label(class="control-label")|safe}}
### BEFORE the for loop {% for item in field -%}
### <div class="radio">
role = RadioField(label='Role',choices=['Department Head','Team Lead','Project Manager'],validators=[DataRequired()])
pin = IntegerField(label='Access Code')
submit = SubmitField('Register')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError('Please use a different username.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError('Please use a different email address.')
def validate_role(self,role,pin):
roles = role.data
pins = pin.data
if pins != 1000 and roles == 'Department Head':
raise ValidationError('This role requires the proper Access Code. Please contact Seymour Stats administration for access.')
elif pins != 2000 and roles == 'Team Lead':
raise ValidationError('This role requires the proper Access Code. Please contact Seymour Stats administration for access.')
class ResetPasswordRequestForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
submit = SubmitField('Request Password Reset')
class ResetPasswordForm(FlaskForm):
password = PasswordField('Password', validators=[DataRequired()])
password2 = PasswordField(
'Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Request Password Reset')
如果我可以提供更多代码来帮助解决,请告诉我。
from flask import Flask, redirect, url_for
from flask_login import LoginManager, UserMixin, login_user, current_user
from dash import Dash, html
app = Flask(__name__)
app.secret_key = 'your_secret_key'
# Flask-Login setup
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
# User model
class User(UserMixin):
def __init__(self, id, role):
self.id = id
self.role = role
# Dummy user database
users = {'admin': User('admin', 'admin'), 'user': User('user', 'user')}
@login_manager.user_loader
def load_user(user_id):
return users.get(user_id)
@app.route('/login')
def login():
user = users['admin'] # Simulate login
login_user(user)
return 'Logged in as admin'
# Initialize Dash app
dash_app1 = Dash(__name__, server=app, url_base_pathname='/dash1/')
dash_app2 = Dash(__name__, server=app, url_base_pathname='/dash2/')
# Function to protect Dash layout based on user role
def protected_dash_layout(dash_app, role):
def serve_layout():
if not current_user.is_authenticated or current_user.role != role:
return html.Div("Access denied")
# Original Dash layout here
return html.Div("This is a protected Dash app for role: " + role)
dash_app.layout = serve_layout
# Protecting Dash app layouts
protected_dash_layout(dash_app1, 'admin')
protected_dash_layout(dash_app2, 'user')
if __name__ == '__main__':
app.run(debug=True)