Authenciation & Admin

Added flask-login for authentication of the web portion. Included flask-admin rather than writing our own views for the various models.
This commit is contained in:
Jarret Raim 2013-02-17 14:45:13 -06:00
parent 151a5726a3
commit aeaae4fbdc
5 changed files with 158 additions and 47 deletions

View File

@ -13,25 +13,65 @@
:license: Apache 2.0, see LICENSE for details
"""
import os
from flask import Flask, render_template
from flask import Flask, render_template, redirect, flash, request
from flask.ext.admin import Admin
from flask.ext.admin.contrib.sqlamodel import ModelView
from flask.ext import login, wtf
from flask.ext.login import login_user
from barbican_api import api
from database import db_session, init_db
from models import User
app = Flask(__name__)
app.secret_key = '79f9823f1f0---DEVELOPMENT---c46cebdd1c8f3d0742e02'
app.register_blueprint(api)
admin = Admin(app, name="Barbican Admin")
admin.add_view(ModelView(User, db_session))
login_manager = login.LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
@app.route("/")
@login.login_required
def hello():
return "Hello world!"
@app.route('/users')
def users_list():
users = User.query.all()
return render_template('users.html', users=users)
#
# Login forms
#
class LoginForm(wtf.Form):
login = wtf.TextField(validators=[wtf.required()])
password = wtf.PasswordField(validators=[wtf.required()])
def validate_login(self, field):
user = self.get_user()
if user is None or user.password != self.password.data:
raise wtf.ValidationError('Invalid username or credentials.')
def get_user(self):
return User.query.filter_by(name=self.login.data).first()
@app.route("/login", methods=["GET", "POST"])
def login():
form = LoginForm(request.form)
if form.validate_on_submit():
user = form.get_user()
login_user(user)
flash('Logged in successfully.')
return redirect('/admin/')
return render_template("login.html", form=form)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
@app.teardown_request
@ -41,5 +81,6 @@ def shutdown_session(exception=None):
if __name__ == '__main__':
if not os.path.exists('/tmp/barbican.db'):
app.logger.info('No database detected at /tmp/barbican.db. Creating one and the admin user.')
init_db()
app.run(debug=True)

View File

@ -29,5 +29,5 @@ def init_db():
# you will have to import them first before calling init_db()
import models
Base.metadata.create_all(bind=engine)
db_session.add(models.User('admin', 'admin@localhost'))
db_session.add(models.User('admin', 'admin@localhost', 'Passw0rd'))
db_session.commit()

View File

@ -17,10 +17,24 @@ class User(Base):
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
email = Column(String(120), unique=True)
password = Column(String(50))
def __init__(self, name=None, email=None):
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
def __init__(self, name=None, email=None, password=None):
self.name = name
self.email = email
self.password = password
def __repr__(self):
return '<User %r>' % self.name

96
templates/login.html Normal file
View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sign in &middot; Twitter Bootstrap</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<!-- Le styles -->
<link href="/static/css/bootstrap.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
}
.form-signin {
max-width: 300px;
padding: 19px 29px 29px;
margin: 0 auto 20px;
background-color: #fff;
border: 1px solid #e5e5e5;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.05);
box-shadow: 0 1px 2px rgba(0,0,0,.05);
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
margin-bottom: 10px;
}
.form-signin input[type="text"],
.form-signin input[type="password"] {
font-size: 16px;
height: auto;
margin-bottom: 15px;
padding: 7px 9px;
}
</style>
<link href="/static/css/bootstrap-responsive.css" rel="stylesheet">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="/static/js/html5shiv.js"></script>
<![endif]-->
<!-- Fav and touch icons -->
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/static/ico/apple-touch-icon-144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/static/ico/apple-touch-icon-114-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/static/ico/apple-touch-icon-72-precomposed.png">
<link rel="apple-touch-icon-precomposed" href="/static/ico/apple-touch-icon-57-precomposed.png">
<link rel="shortcut icon" href="/static/ico/favicon.png">
</head>
<body>
<div class="container">
<form method="post" class="form-signin">
{{ form.hidden_tag() }}
<h2 class="form-signin-heading">Please sign in</h2>
{% if form.errors %}
<div class="alert alert-error alert-block">
<h4>Errors</h4>
<ul>
{% for field_name, field_errors in form.errors|dictsort if field_errors %}
{% for error in field_errors %}
<li>{{ form[field_name].name }}: {{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
{% for f in form if f.type != 'CSRFTokenField' %}
{{ f.label }}{{ f }}
{% endfor %}
<button class="btn btn-large btn-primary" type="submit">Sign in</button>
</form>
</div> <!-- /container -->
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="/static/js/jquery-1.9.1.min.js"></script>
</body>
</html>

View File

@ -1,40 +0,0 @@
{% extends "layout.html" %}
{% block body %}
<div class="row">
<div class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Actions</li>
<li><a href="#"><i class="icon-plus"></i> Add User</a></li>
</ul>
</div>
</div>
<div class="span9">
<div class="page-header">
<h1>Users</h1>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>User ID</th>
<th>Username</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
{% else %}
<em>No users yet.</em>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}