Flask é um micro framework web baseado em Python que permite que você escreva seus aplicativos web de forma rápida e eficiente. Por micro, isso não significa que o Flask careça de funcionalidade. Simplesmente se refere ao fato de que o Flask manteve seu núcleo pequeno e altamente extensível.
O LDAP (Lightweight Directory Access Protocol) pode ter significados diferentes para pessoas diferentes, dependendo de seu uso. É um protocolo de Internet para procurar informações de contato sobre usuários, informações sobre certificados, ponteiros de rede, etc., de um servidor onde os dados são armazenados em uma estrutura de estilo de diretório. Seu uso mais popular é fornecer um “logon único” onde um usuário pode acessar vários aplicativos fazendo login uma vez, pois a senha seria compartilhada entre os serviços.
Neste tutorial, mostrarei como implementar a autenticação de usuários em seu aplicativo Flask usando LDAP. Para demonstrar isso, criarei um pequeno aplicativo com uma página inicial e uma página de login. O usuário precisaria inserir os detalhes de login na página de login. Se as credenciais inseridas pelo usuário forem autenticadas com sucesso no servidor LDAP fornecido, o usuário será conectado. Caso contrário, o usuário verá uma mensagem apropriada.
Presumo que você tenha uma compreensão básica das práticas recomendadas de Flask, LDAP, extensão Flask-Login e configuração de ambiente usando virtualenv ao desenvolver um aplicativo Python.
Servidor LDAP
Para usar o LDAP, você precisará de um servidor; O OpenLDAP é uma implementação de software livre do LDAP. Outras alternativas são o Microsoft Azure Active Directory, um serviço premium. Como precisamos apenas de um servidor de teste, não haverá necessidade de configurar um servidor local. Usaremos um servidor de teste LDAP disponível publicamente da Forum Systems.
Instalando Dependências
Os seguintes pacotes precisam ser instalados para o aplicativo que iremos desenvolver.
$ pip install ldap3 $ pip install Flask-WTF flask-sqlalchemy Flask-Login
Os comandos acima devem instalar todos os pacotes necessários para que este aplicativo funcione.
Estrutura do Aplicativo
Primeiro, o aplicativo precisa ser estruturado de forma que seja fácil de entender.
flask_app/ my_app/ - __init__.py auth/ - __init__.py - models.py - views.py static/ - css/ - js/ templates/ - base.html - home.html - login.html - run.py
Todos os arquivos serão discutidos abaixo. o static
A pasta contém os arquivos CSS e JS padrão do Bootstrap.
O próprio aplicativo
Primeiro, o arquivo de configuração precisa ser escrito:
flask_app/my_app/__init__.py
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' app.config['WTF_CSRF_SECRET_KEY'] = 'random key for form' app.config['LDAP_PROVIDER_URL'] = 'ldap://ldap.forumsys.com:389/' app.config['LDAP_PROTOCOL_VERSION'] = 3 db = SQLAlchemy(app) app.secret_key = 'randon_key' login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = 'auth.login' ctx = app.test_request_context() ctx.push() from my_app.auth.views import auth app.register_blueprint(auth) db.create_all()
No arquivo acima, o aplicativo foi configurado com diferentes opções conforme necessário pelas extensões, bem como pela configuração do LDAP. Isso é seguido pela inicialização das extensões e, finalmente, pela criação do banco de dados.
A última instrução cria um novo banco de dados no local fornecido contra SQLALCHEMY_DATABASE_URI
se ainda não existir um banco de dados naquele local, caso contrário, ele carregará o aplicativo com o mesmo banco de dados.
flask_app/my_app/auth/models.py
import ldap3 from flask_wtf import Form from wtforms import StringField,PasswordField from wtforms import validators from my_app import db, app def get_ldap_connection(): conn = ldap3.initialize(app.config['LDAP_PROVIDER_URL']) return conn class User(db.Model): id = db.Column(db.Integer, primary_key = True) username = db.Column(db.String(100)) def __init__(self, username, password): self.username = username @staticmethod def try_login(username, password): conn = get_ldap_connection() conn.simple_bind_s( 'cn=%s,ou=mathematicians,dc=example,dc=com' % username,password ) def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return self.id class LoginForm(Form): username = StringField('Username',[validators.DataRequired()]) password = PasswordField('Password',[validators.DataRequired()])
O arquivo acima começa com a criação de um User
modelo que contém apenas um username
campo para fins de demonstração. Você pode adicionar quantos campos forem necessários de acordo com o contexto do aplicativo.
Os métodos is_authenticated()
, is_active()
, is_anonymous()
e get_id()
são necessários para a extensão Flask-Login. o try_login()
O método faz o processo de autenticação real criando primeiro uma conexão com o servidor LDAP e, em seguida, usando o nome de usuário e a senha para efetuar login no servidor criando um vínculo simples.
O primeiro argumento adotado pelo simple_bind_s()
O método é o DN, que é fornecido pelo servidor LDAP e varia de acordo com a configuração do registro LDAP. O manuseio do formulário é feito pelo LoginForm
que estende o Form
classe fornecida por Flask-WTForms.
flask_app/my_app/auth/views.py
import ldap3 from flask import (request,render_template,flash, redirect, url_for, Blueprint,g ) from flask_login import (current_user,login_user,logout_user,login_required) from my_app import login_manager,db auth = Blueprint('auth', __name__) from my_app.auth.models import User,LoginForm @login_manager.user_loader def load_user(id): return User.query.get(int(id)) @auth.before_request def get_current_user(): g.user = current_user @auth.route('/') @auth.route('/home') def home(): return render_template('home.html') @auth.route('/login', methods = ['GET','POST']) def login(): if current_user.is_authenticated: flash('You are already logged in.') return redirect(url_for('auth.home')) form = LoginForm(request.form) if request.method == 'POST' and form.validate(): username = request.form['username'] password = request.form['password'] try: User.try_login(username,password) except: flash( 'Invalid username or password. Please try again.', 'danger') return render_template('login.html', form=form) user = User.query.filter_by(username = username) if not user: user = User(username = username, password = password) db.session.add(user) db.commit() login_user(user) flash('You have successfully logged in.', 'success') return redirect(url_for('auth.home')) if form.errors: flash(form.errors, 'danger') return render_template('login.html', form=form) @auth.route('/logout') @login_required def logout(): logout_user() return redirect(url_for('auth.home'))
No arquivo acima, os métodos load_user()
e get_current_user()
são necessários pela extensão Flask-Login. A seguir estão os manipuladores de nosso aplicativo, que são decorados por suas respectivas rotas.
home()
apenas renderiza a página inicial para o usuário. O conteúdo da página inicial é determinado pelo modelo flask_app/my_app/templates/home.html
que discutiremos em breve.
O manipulador de interesse primário é login()
pois ele lida com o processo de login completo. Se um usuário logado tentar acessar esta página, a página será redirecionada automaticamente para a página inicial. Caso contrário, o processo de login começará onde o nome de usuário e a senha LDAP do usuário são obtidos como entrada de formulário de flask_app/my_app/templates/login.html
.
Usando essas credenciais, o aplicativo tenta autenticar o usuário do servidor LDAP fornecido na configuração que vimos anteriormente. Se o usuário for autenticado, o aplicativo criará um novo registro para o usuário se um usuário estiver acessando o aplicativo pela primeira vez, caso contrário, ele apenas fará o login do usuário com o registro existente do usuário.
Mensagens flash são mostradas ao usuário como e quando necessário para manter o usuário envolvido com o aplicativo.
logout()
o hander simplesmente limpa a sessão do usuário atualmente conectado como resultado do qual o usuário está desconectado.
flask_app/my_app/templates/base.html
Flask Authentication with LDAP Tutorial {% block scripts %} {% endblock %}
{% for category, message in get_flashed_messages(with_categories=true) %}{% block container %}{% endblock %}{{ message }}{% endfor %}
Acima está o arquivo base que contém o cabeçalho, rodapé e outros componentes básicos que permanecem comuns em todo o aplicativo. Isso ajuda a manter os modelos muito modulares e fáceis de entender, pois cada modelo contém apenas o código relevante para seu manipulador e funcionalidade.
Embora todos os componentes comuns estejam definidos aqui, adicionei um bloco vazio para scripts
que pode ser estendido em qualquer modelo que herda base.html
. Observe como o piscar de mensagens está sendo feito acima e como as classes CSS do Bootstrap estão sendo reproduzidas dinamicamente para tornar a caixa de alerta de mensagem flash apropriadamente estilizada.
o container
bloco será estendido pelo restante dos modelos para adicionar seus respectivos conteúdos.
flask_app/my_app/templates/home.html
{% extends 'base.html' %} {% block container %}Welcome to the Flask-LDAP Authentication Demo
{% if current_user.is_authenticated %}Hey {{ current_user.username }}!!
Click here to logout {% else %} Click here to login with LDAP {% endif %} {% endblock %}
Observe como o modelo base foi estendido e o conteúdo da página inicial foi adicionado dentro do contêiner do bloco.
Se o usuário estiver logado, ele será saudado com o nome de usuário e uma mensagem será exibida para sair. Caso contrário, o usuário verá uma mensagem para efetuar login com o link para a página de login.
flask_app/my_app/templates/login.html
{% extends 'home.html' %} {% block container %}{% endblock %}
O modelo de login simplesmente contém um formulário com campos para username
e password
.
Executando o aplicativo
Para executar o aplicativo, execute o script run.py
. O conteúdo deste script é:
from my_app import app app.run(debug=True)
Agora é só executar na linha de comando:
python run.py
Por fim, abra http://127.0.0.1:5000/ em seu navegador preferido e veja seu aplicativo em ação. Tudo deve ser auto-explicativo. Para fazer login, você pode usar os seguintes usuários:
- riemann
- gauss
- euler
- Euclides
Todas as senhas de usuário são senha.
Conclusão
Ao longo deste tutorial, construímos um aplicativo da Web pequeno, mas eficaz, usando o Flask com a ajuda da extensão Flask-Login. Este aplicativo simplesmente pega um nome de usuário e senha e autentica o usuário no servidor LDAP fornecido. Use sua imaginação para ajustar e estender o aplicativo de acordo com suas necessidades.