Flask学习笔记(登陆和用户权限)
1、用户认证模块 | Flask-Login
1.1 准备用于登陆的用户模型
模型继承UserMixin
1 from app import db 2 from werkzeug.security import generate_password_hash,check_password_hash 3 from flask_login import UserMixin 4 from . import login_manger 5 6 @login_manger.user_loader 7 def load_user(user_id): 8 return User.query.get(int(user_id)) 9 10 class Role(db.Model): 11 __tablename__ = 'roles' 12 id = db.Column(db.Integer,primary_key=True) 13 name = db.Column(db.String(64),unique=True) 14 users = db.relationship('User',backref='role') 15 def __repr__(self): 16 return '<Role %r>'%self.name 17 18 class User(UserMixin,db.Model): 19 __tablename__ = 'users' 20 id = db.Column(db.Integer,primary_key=True) 21 username = db.Column(db.String(64),unique=True,index=True) 22 password_hash = db.Column(db.String(128)) 23 role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) 24 email = db.Column(db.String(128)) 25 26 @property 27 def password(self): 28 raise AttributeError('密码不可读') 29 30 @password.setter 31 def password(self,password): 32 self.password_hash = generate_password_hash(password) 33 34 def verify_password(self,password): 35 return check_password_hash(self.password_hash,password) 36 37 def __repr__(self): 38 return '<Role %r>'%self.username
初始化登陆
1 from flask import Flask,render_template 2 from flask_sqlalchemy import SQLAlchemy 3 from config import Config 4 from flask_login import LoginManager 5 6 db = SQLAlchemy() 7 login_manger = LoginManager() 8 login_manger.session_protection = 'strong' 9 login_manger.login_view = 'auth.login' 10 11 def create_app(): 12 app = Flask(__name__) 13 app.config.from_object(Config) 14 Config.init_app(app) 15 db.init_app(app) 16 login_manger.init_app(app) 17 from .main import main as main_blueprint 18 app.register_blueprint(main_blueprint) 19 from .auth import auth as auth_blueprint 20 app.register_blueprint(auth_blueprint,url_prefix='/auth') 21 return app
1.2 保护路由
@login_required
1 from datetime import datetime 2 from flask import render_template,session,redirect,url_for 3 from . import main 4 from .forms import NameForm 5 from .. import db 6 from .. import models 7 from flask_login import login_required 8 9 10 @main.route('/',methods=['GET','POST']) 11 @login_required 12 def index(): 13 form = NameForm() 14 if form.validate_on_submit(): 15 session['name'] = form.name.data 16 session['ip'] = form.ip.data 17 form.name.data='' 18 form.ip.data='' 19 return redirect(url_for('.index')) 20 return render_template('index.html',form=form,name=session.get('name'),ip=session.get('ip'))
1.3 登陆页面
在前端可以使用current_user对象
1 {% extends 'base.html' %} 2 {% block head %}{{ super() }}{% endblock %} 3 {% block title %}登陆{% endblock %} 4 {% block body %} 5 <h1> 6 7 </h1> 8 {% if current_user.is_authenticated %} 9 <h1>欢迎{{ current_user.username }}</h1> 10 <p><a href="{{ url_for('auth.logout') }}">登出</a></p> 11 {% else %} 12 <h1>登录页面</h1> 13 <form method="post" action=""> 14 {{ form.hidden_tag() }} 15 <p>{{ form.email.label }}{{ form.email }}</p> 16 <p>{{ form.password.label }}{{ form.password }}</p> 17 <p>{{ form.sumbit }}</p> 18 <p>{{ form.remember_me.label }}{{ form.remember_me }}</p> 19 </form> 20 <p><a href="{{ url_for('auth.register') }}">注册</a></p> 21 {% endif %} 22 {% endblock %}
1.4 登入登出注册用户
login_user('用户模型对象','True/False')
logout_user()
1 from flask import render_template,redirect,request,url_for,flash 2 from flask_login import login_user,login_required,logout_user 3 from . import auth 4 from ..models import User,db 5 from .forms import LoginForm,RegistrationForm 6 7 @auth.route('/login',methods=['GET','POST']) 8 def login(): 9 form = LoginForm() 10 user = User.query.filter_by(email=form.email.data).first() 11 if user is not None and user.verify_password(form.password.data): 12 login_user(user,form.remember_me.data) 13 return redirect(url_for('main.index')) 14 return render_template('auth/login.html',form=form) 15 16 @auth.route('/logout') 17 @login_required 18 def logout(): 19 logout_user() 20 flash('你已经登出了') 21 return redirect(url_for('main.index')) 22 23 24 @auth.route('/register',methods=['GET','POST']) 25 def register(): 26 form = RegistrationForm() 27 if form.validate_on_submit(): 28 user = User(email=form.email.data,username=form.username.data,password=form.password1.data) 29 db.session.add(user) 30 db.session.commit() 31 return redirect(url_for('auth.login')) 32 return render_template('auth/register.html',form=form)
2、用户角色权限
还是主要靠程序逻辑来做权限
2.1 在角色模型中添加权限、赋予角色、角色验证
1 from app import db 2 from werkzeug.security import generate_password_hash,check_password_hash 3 from flask_login import UserMixin,AnonymousUserMixin 4 from . import login_manger 5 6 @login_manger.user_loader 7 def load_user(user_id): 8 return User.query.get(int(user_id)) 9 10 class Permission: 11 FLLOW = 0x01 12 COMMENT = 0x02 13 WRITE_ARTICLES = 0x04 14 MODERATE_COMMENTS = 0x08 15 ADMINISTER = 0x80 16 17 class Role(db.Model): 18 __tablename__ = 'roles' 19 id = db.Column(db.Integer,primary_key=True) 20 name = db.Column(db.String(64),unique=True) 21 default = db.Column(db.Boolean,default=False,index=True) 22 permissions = db.Column(db.Integer) 23 users = db.relationship('User',backref='role') 24 25 #创建数据库角色 26 @staticmethod 27 def insert_roles(): 28 roles = { 29 'User':(Permission.FLLOW|Permission.COMMENT|Permission.WRITE_ARTICLES,True), 30 'Admin':(0xff,False) 31 } 32 for r in roles: 33 role = Role.query.filter_by(name = r).first() 34 if role is None: 35 role = Role(name=r) 36 role.permissions = roles[r][0] 37 role.default=roles[r][1] 38 db.session.add(role) 39 db.session.commit() 40 41 def __repr__(self): 42 return '<Role %r>'%self.name 43 44 class User(UserMixin,db.Model): 45 __tablename__ = 'users' 46 id = db.Column(db.Integer,primary_key=True) 47 username = db.Column(db.String(64),unique=True,index=True) 48 password_hash = db.Column(db.String(128)) 49 role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) 50 email = db.Column(db.String(128)) 51 52 #创建的新用户默认是用户权限 53 def __init__(self,**kwargs): 54 super(User,self).__init__(**kwargs) 55 self.role = Role.query.filter_by(default=True).first() 56 57 @property 58 def password(self): 59 raise AttributeError('密码不可读') 60 61 @password.setter 62 def password(self,password): 63 self.password_hash = generate_password_hash(password) 64 65 def verify_password(self,password): 66 return check_password_hash(self.password_hash,password) 67 68 #角色验证 69 def can(self,permissions): 70 return self.role is not None and (self.role.permissions & permissions) == permissions 71 72 def is_admin(self): 73 return self.can(Permission.ADMINISTER) 74 75 def __repr__(self): 76 return '<User %r>'%self.username 77 78 #匿名角色,主要为了与上面统一 79 class AnonymousUser(AnonymousUserMixin): 80 def can(self,permissions): 81 return False 82 83 def is_admin(self): 84 return False 85 86 login_manger.anonymous_user = AnonymousUser
python manage.py shell
Role.insert_roles()
2.2 定义用户权限验证装饰器
1 from functools import wraps 2 from flask import abort 3 from flask_login import current_user 4 from .models import Permission 5 6 def permission_required(permission): 7 def decorator(f): 8 @wraps(f) 9 def decorated_function(*args,**kwargs): 10 if not current_user.can(permission): 11 abort(403) 12 return f(*args,**kwargs) 13 return decorated_function 14 return decorator 15 16 def admin_required(f): 17 return permission_required(Permission.ADMINISTER)(f)
2.3 给需要权限访问的页面加装饰器
1 from datetime import datetime 2 from flask import render_template,session,redirect,url_for 3 from . import main 4 from .forms import NameForm 5 from .. import db 6 from .. import models 7 from flask_login import login_required 8 from ..decorators import admin_required,permission_required 9 from ..models import Permission 10 11 @main.route('/',methods=['GET','POST']) 12 @login_required 13 def index(): 14 form = NameForm() 15 if form.validate_on_submit(): 16 session['name'] = form.name.data 17 session['ip'] = form.ip.data 18 form.name.data='' 19 form.ip.data='' 20 return redirect(url_for('.index')) 21 return render_template('index.html',form=form,name=session.get('name'),ip=session.get('ip')) 22 23 24 @main.route('/admin') 25 @login_required 26 @admin_required 27 def admin_only(): 28 return render_template('admin.html') 29 30 31 @main.route('/user') 32 @login_required 33 @permission_required(Permission.WRITE_ARTICLES) 34 def user_page(): 35 return render_template('user.html')