也有可能没有任何一种解决方案是100%合适的,即您需要进行更改或扩展。
在这种情况下,我的建议是从基本模型开始,根据您的需求进行扩展。
某些插件的想法和方法可以帮助您解决问题。
这种方法的优点是,您将学到更多关于底层发生了什么,而不是只从某些插件中导入。
插件很棒,社区已经付出了很多努力扩展功能。
没有任何疑问。
把答案看作是动力,因为您的问题可以从最小代码版本0.0.1开始:
class RolesUsers(Base):
__tablename__ = 'roles_users'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id'))
role_id = db.Column(db.Integer(), db.ForeignKey('role.id'))
class Role(RoleMixin, Base):
__tablename__ = 'role'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
def __repr__(self):
return self.name
class User(UserMixin, Base):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), index=True, unique=True)
roles = db.relationship('Role', secondary='roles_users',
backref=db.backref('users', lazy='dynamic'))
请查看M2M
更新:来自评论的请求
现在你有一个小型应用程序,代表了提到的第一个版本0.0.1 :)
由于你有一段时间没有使用FLASK了,我尽力通过注释提醒你一些基本细节。
import datetime
from functools import wraps
from flask import Flask, redirect, url_for, session, render_template_string
from flask_sqlalchemy import SQLAlchemy
class ConfigClass(object):
""" Flask application config """
SECRET_KEY = 'This is an INSECURE secret!! DO NOT use this in production!!'
SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
SQLALCHEMY_TRACK_MODIFICATIONS = False
def create_app():
""" Flask application factory """
app = Flask(__name__)
app.config.from_object(__name__+'.ConfigClass')
db = SQLAlchemy(app)
@app.before_request
def before_request():
try:
print("Current Role: ", session['role'])
except:
print("Current Role: Guest")
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
active = db.Column('is_active', db.Boolean(), nullable=False, server_default='1')
email = db.Column(db.String(255, collation='NOCASE'), nullable=False, unique=True)
email_confirmed_at = db.Column(db.DateTime())
password = db.Column(db.String(255), nullable=False, server_default='')
first_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='')
last_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='')
roles = db.relationship('Role', secondary='user_roles')
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)
class UserRoles(db.Model):
__tablename__ = 'user_roles'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
db.drop_all()
db.create_all()
if not User.query.filter(User.email == 'member@example.com').first():
user = User(
email='member@example.com',
email_confirmed_at=datetime.datetime.utcnow(),
password='Password1',
)
db.session.add(user)
db.session.commit()
if not User.query.filter(User.email == 'admin@example.com').first():
user = User(
email='admin@example.com',
email_confirmed_at=datetime.datetime.utcnow(),
password='Password1',
)
user.roles.append(Role(name='Admin'))
user.roles.append(Role(name='Member'))
db.session.add(user)
db.session.commit()
def access_required(role="ANY"):
"""
see: https://flask.palletsprojects.com/en/2.1.x/patterns/viewdecorators/
"""
def wrapper(fn):
@wraps(fn)
def decorated_view(*args, **kwargs):
if session.get("role") == None or role == "ANY":
session['header'] = "Welcome Guest, Request a new role for higher rights!"
return redirect(url_for('index'))
if session.get("role") == 'Member' and role == 'Member':
print("access: Member")
session['header'] = "Welcome to Member Page!"
return redirect(url_for('index'))
if session.get("role") == 'Admin' and role == 'Admin':
session['header'] = "Welcome to Admin Page!"
print("access: Admin")
else:
session['header'] = "Oh no no, you haven'tn right of access!!!"
return redirect(url_for('index'))
return fn(*args, **kwargs)
return decorated_view
return wrapper
@app.route('/')
def index():
print("index:", session.get("role", "nema"))
return render_template_string('''
<h3>{{ session["header"] if session["header"] else "Welcome Guest!" }}</h3>
<a href="/admin_role">Get Admin Role</a>    |   
<a href="/admin_page">Admin Page</a> <br><br>
<a href="/member_role">Get Member Role</a>    |   
<a href="/member_page">Member Page</a> <br><br>
<a href="/guest_role">Get Guest Role</a> <br><br>
<a href="/data">Try looking at DATA with different roles</a>
''')
@app.route('/data')
def data():
return render_template_string("""
<a href="/admin_role">Admin Role</a>
<a href="/member_role">Member Role</a>
<a href="/guest_role">Guest Role</a>
<br><p>The data page will display a different context depending on the access rights.</p><br>
{% if not session['role'] %}
<h2>You must have diffrent role for access to the data.</h2>
<a href="{{ url_for('.index') }}">Go back?</a>
{% endif %}
{% if session['role'] == 'Member' or session['role'] == 'Admin' %}
<h2>USERS:</h2>
<table>
<tr>
<th>ID</th>
<th>EMAIL</th>
</tr>
{% for u in users %}
<tr>
<td>{{ u.id }}</td>
<td>{{ u.email }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% if session['role'] == 'Admin' %}
<h2>ROLE:</h2>
<table>
<tr>
<th>ID</th>
<th>NAME</th>
</tr>
{% for r in roles %}
<tr>
<td>{{ r.id }}</td>
<td>{{ r.name }}</td>
</tr>
{% endfor %}
</table>
<h2>USER ROLES:</h2>
<table>
<tr>
<th>ID</th>
<th>USER ID</th>
<th>ROLE ID</th>
</tr>
{% for ur in user_roles %}
<tr>
<td>{{ ur.id }}</td>
<td>{{ ur.user_id }}</td>
<td>{{ ur.role_id }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
""",
users=User.query,
roles= Role.query,
user_roles=UserRoles.query)
@app.route("/member_role")
def member_role():
"""
Anyone can access the url and get the role of a MEMBER.
"""
r = Role.query.get(2)
session['role'] = r.name
session['header'] = "Welcome to Member Access!"
return render_template_string('<h2>{{ session["header"] }}</h2> <a href="/">Go back?</a>')
@app.route("/member_page")
@access_required(role="Member")
def member_page():
return render_template_string('<h1>{{ session["header"] }}</h1> <a href="/">Go back?</a>')
@app.route("/admin_role")
def admin_role():
"""
Anyone can access the url and get the role of a ADMIN.
"""
r = Role.query.get(1)
session['role'] = r.name
session['header'] = "Welcome to Admin Access!"
return render_template_string('<h1>{{ session["header"] }}</h1> <a href="/">Go back?</a>')
@app.route("/admin_page")
@access_required(role="Admin")
def admin_page():
"""
This url requires an ADMIN role.
"""
return render_template_string('<h1>{{ session["header"] }}</h1> <a href="/">Go back?</a>')
@app.route("/guest_role")
def guest_role():
"""
For the GUEST, we will only delete the session and thus 'kill' the roles.
"""
session.clear()
return redirect(url_for('index'))
return app
if __name__ == '__main__':
app = create_app()
app.run(host='0.0.0.0', port=5000, debug=True)
现在我们可以开始游戏了,因为有一些规则,包括:只有具有管理员角色的用户才能访问管理员页面,成员和他的页面也是如此。此外,您有一个由第一个答案版本中提到的模型组成的数据列表。这个数据列表也可以用不同的角色查看。细节:如果您拥有管理员角色,则可以看到所有要显示的数据;如果您拥有成员角色,则只能查看用户,并且如果您是访客,则无法查看任何数据。
下面是它的图示形式。
![enter image description here](https://istack.dev59.com/jn0tn.webp)
我希望这个简单的例子能够对你和其他stackcoverflow社区成员的进一步学习有所帮助。我坚信你很快就会拥有一个更好的版本。
愉快的编程...