Tutorial : Sử dụng flask cho người mới bắt đầu ( Phần 5)

Phần tiếp này tôi sẽ cùng các bạn làm phần tạo user login cho ứng dụng post. để tạo phần login chúng ta sẽ sử dụng extensions Flask-Login và Flask-OpenID. Flask-login sẽ điều khiển logged in state và Flask-OpenID sẽ cung cấp authentication.

1.login
Đầu tiên configure file app/__init__.py:

 import os
from flask.ext.login import LoginManager
from flask.ext.openid import OpenID
from config import basedir

lm = LoginManager()
lm.init_app(app)
oid = OpenID(app, os.path.join(basedir, 'tmp'))

Trong model User class (file app/models.py):

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    posts = db.relationship('Post', backref='author', lazy='dynamic')

    @property
    def is_authenticated(self):
        return True

    @property
    def is_active(self):
        return True

    @property
    def is_anonymous(self):
        return False

    def get_id(self):
        try:
            return unicode(self.id)  # python 2
        except NameError:
            return str(self.id)  # python 3

    def __repr__(self):
        return '<User %r>' % (self.nickname)

Bây giờ chúng ta sẽ sử dụng Flask-Login and Flask-OpenID extensions. Sử dụng Flask-Login (file app/views.py):

from flask import render_template, flash, redirect, session, url_for, request, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from app import app, db, lm, oid
from .forms import LoginForm
from .models import User

@app.route('/login', methods=['GET', 'POST'])
@oid.loginhandler
def login():
    if g.user is not None and g.user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        session['remember_me'] = form.remember_me.data
        return oid.try_login(form.openid.data, ask_for=['nickname', 'email'])
    return render_template('login.html',
                           title='Sign In',
                           form=form,
                           providers=app.config['OPENID_PROVIDERS'])

Ở đây: oid.loginhandler cho Flask-OpenID biết rằng đây là hàm login.
g là biến global được Flask lưu giữ và chia sẻ thông tin trong suốt vòng đời request.
url_for là function chứa url flask sẽ redirect tới.
remember_me kiểu boolean chứa trong flask session.
oid.try_login sẽ gọi tới user authentication thông qua Flask-OpenID.

Ở đây OpenID authentication khi đồng bọ sẽ gọi tới oid.after_login nếu authentication thành công. Bước tiếp chúng ta sẽ viết hàng oid.after_login (file app/views.py):

@oid.after_login
def after_login(resp):
    if resp.email is None or resp.email == "":
        flash('Invalid login. Please try again.')
        return redirect(url_for('login'))
    user = User.query.filter_by(email=resp.email).first()
    if user is None:
        nickname = resp.nickname
        if nickname is None or nickname == "":
            nickname = resp.email.split('@')[0]
        user = User(nickname=nickname, email=resp.email)
        db.session.add(user)
        db.session.commit()
    remember_me = False
    if 'remember_me' in session:
        remember_me = session['remember_me']
        session.pop('remember_me', None)
    login_user(user, remember = remember_me)
    return redirect(request.args.get('next') or url_for('index'))

2.Logging out

Chúng ta sẽ tạo phần log out cho người dùng.
trong phần (app/views.py):

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

Bây giờ chúng ta còn thiếu đường link trên thanh navigation trên base layout (file app/templates/base.html):

<html>
  <head>
    {% if title %}
    <title>{{ title }} - microblog</title>
    {% else %}
    <title>microblog</title>
    {% endif %}
  </head>
  <body>
    <div>Microblog:
        <a href="{{ url_for('index') }}">Home</a>
        {% if g.user.is_authenticated %}
        | <a href="{{ url_for('logout') }}">Logout</a>
        {% endif %}
    </div>
    <hr>
    {% with messages = get_flashed_messages() %}
    {% if messages %}
    <ul>
    {% for message in messages %}
        <li>{{ message }} </li>
    {% endfor %}
    </ul>
    {% endif %}
    {% endwith %}
    {% block content %}{% endblock %}
  </body>
</html>

Tổng kết
Chúng ta có đủ chức năng loggin. Trong bài viết tới tôi sẽ giới thiệu phần tạo profile và avatar cho user.