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:
parent
151a5726a3
commit
aeaae4fbdc
51
barbican.py
51
barbican.py
@ -13,25 +13,65 @@
|
|||||||
:license: Apache 2.0, see LICENSE for details
|
:license: Apache 2.0, see LICENSE for details
|
||||||
"""
|
"""
|
||||||
import os
|
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 barbican_api import api
|
||||||
from database import db_session, init_db
|
from database import db_session, init_db
|
||||||
from models import User
|
from models import User
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
app.secret_key = '79f9823f1f0---DEVELOPMENT---c46cebdd1c8f3d0742e02'
|
||||||
app.register_blueprint(api)
|
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("/")
|
@app.route("/")
|
||||||
|
@login.login_required
|
||||||
def hello():
|
def hello():
|
||||||
return "Hello world!"
|
return "Hello world!"
|
||||||
|
|
||||||
|
|
||||||
@app.route('/users')
|
#
|
||||||
def users_list():
|
# Login forms
|
||||||
users = User.query.all()
|
#
|
||||||
return render_template('users.html', users=users)
|
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
|
@app.teardown_request
|
||||||
@ -41,5 +81,6 @@ def shutdown_session(exception=None):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if not os.path.exists('/tmp/barbican.db'):
|
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()
|
init_db()
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
@ -29,5 +29,5 @@ def init_db():
|
|||||||
# you will have to import them first before calling init_db()
|
# you will have to import them first before calling init_db()
|
||||||
import models
|
import models
|
||||||
Base.metadata.create_all(bind=engine)
|
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()
|
db_session.commit()
|
16
models.py
16
models.py
@ -17,10 +17,24 @@ class User(Base):
|
|||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
name = Column(String(50), unique=True)
|
name = Column(String(50), unique=True)
|
||||||
email = Column(String(120), 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.name = name
|
||||||
self.email = email
|
self.email = email
|
||||||
|
self.password = password
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<User %r>' % self.name
|
return '<User %r>' % self.name
|
||||||
|
96
templates/login.html
Normal file
96
templates/login.html
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Sign in · 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>
|
@ -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 %}
|
|
Loading…
Reference in New Issue
Block a user