python flask web基本结构 登录模块 常用

需要的包

flask-login
werkzeug
itsdangerous
flask-mail
flask-bootstrap
flask-wtf

1、 app/models.py
from werkzeug.security import generate_password_hash, check_password_hash
from flask.ext.login import UserMixin,AnonymousUserMixin
from . import login_manager
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
from . import db
login_manager.anonymous_user = AnonymousUser
class User(UserMixin, db.Model):
tablename = 'users'
id = db.Column(db.Integer, primary_key = True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean, default=False)
def init(self, kwargs):
super(User, self).init(
kwargs)
if self.role is None:
if self.email == current_app.config['FLASKY_ADMIN']:
self.role = Role.query.filter_by(permissions=0xff).first()
if self.role is None:
self.role = Role.query.filter_by(default=True).first()
def can(self, permissions):
return self.role is not None and (self.role.permissions & permissions) ==permissions
def is_administrator(self):
return self.can(Permission.ADMINISTER)
@property
def password(self):
raise AttributeError('password is not a readable attribute')
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def verify_password(self, password):
return check_password_hash(self.password_hash, password)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
def generate_confirmation_token(self, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'confirm': self.id})
def confirm(self, token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token)
except:
return False
if data.get('confirm') != self.id:
return False
self.confirmed = True
db.session.add(self)
return True
class AnonymousUser(AnonymousUserMixin):
def can(self, permissions):
return False
def is_administrator(self):
return False
class Permission:
FOLLOW = 0x01
COMMENT = 0x02
WRITE_ARTICLES = 0x04
MODERATE_COMMENTS = 0x08
ADMINISTER = 0x80
class Role(db.Model):
tablename = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic')
@staticmethod
def insert_roles():
roles = {
'User': (Permission.FOLLOW |Permission.COMMENT |Permission.WRITE_ARTICLES, True),
'Moderator': (Permission.FOLLOW |Permission.COMMENT |Permission.WRITE_ARTICLES |Permission.MODERATE_COMMENTS, False),
'Administrator': (0xff, False)
}
for r in roles:
role = Role.query.filter_by(name=r).first()
if role is None:
role = Role(name=r)
role.permissions = roles[r][0]
role.default = roles[r][1]
db.session.add(role)
db.session.commit()

2、app/auth/init.py ##蓝本
from flask import Blueprint
auth = Blueprint('auth', name)
from . import views

3、 app/auth/views.py #视图
from flask.ext.login import logout_user,login_required
from flask import render_template, redirect, request, url_for, flash
from flask.ext.login import login_user,current_user
from . import auth
from ..models import User
from .forms import LoginForm
from ..email import send_email
@auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is None:
user =User.query.filter_by(username=form.username .data).first()
if user is not None and user.verify_password(form.password.data):
login_user(user, form.remember_me.data)
return redirect(request.args.get('next') or url_for('main.index'))
flash('Invalid username or password.')
return render_template('auth/login.html', form=form)
@app.route('/secret')
@login_required
def secret():
return 'Only authenticated users are allowed!'
@auth.route('/logout')
@login_required
def logout():
logout_user()
flash('You have been logged out.')
return redirect(url_for('main.index'))
@auth.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(email=form.email.data,username=form.username.data,password=form.password.data)
db.session.add(user)
db.session.commit()
token = user.generate_confirmation_token()
send_email(user.email, 'Confirm Your Account','auth/email/confirm', user=user, token=token)
flash('A confirmation email has been sent to you by email.')
return redirect(url_for('auth.login'))
return render_template('auth/register.html', form=form)
@auth.route('/confirm/')
@login_required
def confirm(token):
if current_user.confirmed:
return redirect(url_for('main.index'))
if current_user.confirm(token):
flash('You have confirmed your account. Thanks!')
else:
flash('The confirmation link is invalid or has expired.')
return redirect(url_for('main.index'))
@auth.before_app_request
def before_request():
if current_user.is_authenticated()
and not current_user.confirmed
and request.endpoint[:5] != 'auth.':
and request.endpoint != 'static':
return redirect(url_for('auth.unconfirmed'))
@auth.route('/unconfirmed')
def unconfirmed():
if current_user.is_anonymous() or current_user.confirmed:
return redirect(url_for('main.index'))
return render_template('auth/unconfirmed.html')
@auth.route('/confirm')
@login_required
def resend_confirmation():
token = current_user.generate_confirmation_token()
send_email(current_user.email, 'Confirm Your Account','auth/email/confirm', user=current_user, token=token)
flash('A new confirmation email has been sent to you by email.')
return redirect(url_for('main.index'))

4 app/__init__py #附加蓝本
from flask.ext.login import LoginManager
from .auth import auth as auth_blueprint
login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'
def create_app(config_name):
# ...
login_manager.init_app(app)
app.register_blueprint(auth_blueprint, url_prefix='/auth')
return app

5 app/auth/forms.py #登录表单
from flask.ext.wtf import Form
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import Required, Length, Email, Regexp, EqualTo
from wtforms import ValidationError
from ..models import User

class LoginForm(Form):
email = StringField('Email', validators=[Required(), Length(1, 64),Email()])
password = PasswordField('Password', validators=[Required()])
remember_me = BooleanField('Keep me logged in')
submit = SubmitField('Log In')

class RegistrationForm(Form):
email = StringField('Email', validators=[Required(), Length(1, 64),Email()])
username = StringField('Username', validators=[Required(), Length(1, 64),Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0,'Usernames must have only letters:numbers, dots or underscores')])
password = PasswordField('Password', validators=[Required(), EqualTo('password2',message='Passwords must match.')])
password2 = PasswordField('Confirm password', validators=[Required()])
submit = SubmitField('Register')
def validate_email(self, field):
if User.query.filter_by(email=field.data).first():
raise ValidationError('Email already registered.')
def validate_username(self, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError('Username already in use.')

6 app/templates/base.html ##基础模板中添加登录、登出
{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block head %}
{{ super() }}



{% endblock %}

{% block navbar %}


{% endblock %}

{% block content %}


{% for message in get_flashed_messages() %}


{{ message }}

{% endfor %}

{% block page_content %}{% endblock %}


{% endblock %}

{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}

7 app/templates/auth/login.html #登录页面
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Login{% endblock %}
{% block page_content %}



{{ wtf.quick_form(form) }}


New user?

Click here to register


{% endblock %}

8 app/templates/index.html ##首页
Hello,
{% if current_user.is_authenticated() %}
{{ current_user.username }}
{% else %}
Stranger
{% endif %}!

9 app/templates/auth/email/confirm.txt #确认邮件
Dear {{ user.username }},
Welcome to Flasky!
To confirm your account please click on the following link:
{{ url_for('auth.confirm', token=token, _external=True) }}
Sincerely,
The Flasky Team
Note: replies to this email address are not monitored.

10 app/decorators.py ##自定义权限修饰器
from functools import wraps
from flask import abort
from flask.ext.login import current_user
def permission_required(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args, *kwargs):
if not current_user.can(permission):
abort(403)
return f(
args, **kwargs)
return decorated_function
return decorator
def admin_required(f):
return permission_required(Permission.ADMINISTER)(f)

11、app/main/init.py
@main.app_context_processor
def inject_permissions():
return dict(Permission=Permission)

数据库: python manage.py db upgrade

手动添加用户:

(venv) $ python manage.py shell

u = User(email='[email protected]', username='john', password='cat')
db.session.add(u)
db.session.commit()

插入角色

(venv) $ python manage.py shell

Role.insert_roles()
Role.query.all()

权限表

image.png
image.png

你可能感兴趣的:(python flask web基本结构 登录模块 常用)