Added Persona example
This commit is contained in:
parent
e17024e85a
commit
5f648a8eb8
6 changed files with 198 additions and 0 deletions
59
examples/persona/persona.py
Normal file
59
examples/persona/persona.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
from flask import Flask, render_template, session, request, json, abort, g
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.update(
|
||||
DEBUG=True,
|
||||
SECRET_KEY='my development key',
|
||||
PERSONA_JS='https://login.persona.org/include.js',
|
||||
PERSONA_VERIFIER='https://verifier.login.persona.org/verify',
|
||||
)
|
||||
app.config.from_envvar('PERSONA_SETTINGS', silent=True)
|
||||
|
||||
|
||||
@app.before_request
|
||||
def get_current_user():
|
||||
g.user = None
|
||||
email = session.get('email')
|
||||
if email is not None:
|
||||
g.user = email
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
"""Just a generic index page to show."""
|
||||
return render_template('index.html')
|
||||
|
||||
|
||||
@app.route('/_auth/login', methods=['GET', 'POST'])
|
||||
def login_handler():
|
||||
"""This is used by the persona.js file to kick off the
|
||||
verification securely from the server side. If all is okay
|
||||
the email address is remembered on the server.
|
||||
"""
|
||||
resp = requests.post(app.config['PERSONA_VERIFIER'], data={
|
||||
'assertion': request.form['assertion'],
|
||||
'audience': request.host_url,
|
||||
}, verify=True)
|
||||
if resp.ok:
|
||||
verification_data = json.loads(resp.content)
|
||||
if verification_data['status'] == 'okay':
|
||||
session['email'] = verification_data['email']
|
||||
return 'OK'
|
||||
|
||||
abort(400)
|
||||
|
||||
|
||||
@app.route('/_auth/logout', methods=['POST'])
|
||||
def logout_handler():
|
||||
"""This is what persona.js will call to sign the user
|
||||
out again.
|
||||
"""
|
||||
session.clear()
|
||||
return 'OK'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
50
examples/persona/static/persona.js
Normal file
50
examples/persona/static/persona.js
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
$(function() {
|
||||
/* convert the links into clickable buttons that go to the
|
||||
persona service */
|
||||
$('a.signin').on('click', function() {
|
||||
navigator.id.request();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('a.signout').on('click', function() {
|
||||
navigator.id.logout();
|
||||
return false;
|
||||
});
|
||||
|
||||
/* watch persona state changes */
|
||||
navigator.id.watch({
|
||||
loggedInUser: $CURRENT_USER,
|
||||
onlogin: function(assertion) {
|
||||
/* because the login needs to verify the provided assertion
|
||||
with the persona service which requires an HTTP request,
|
||||
this could take a bit. To not confuse the user we show
|
||||
a progress box */
|
||||
var box = $('<div class=signinprogress></div>')
|
||||
.hide()
|
||||
.text('Please wait ...')
|
||||
.appendTo('body')
|
||||
.fadeIn('fast');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $URL_ROOT + '_auth/login',
|
||||
data: {assertion: assertion},
|
||||
success: function(res, status, xhr) { window.location.reload(); },
|
||||
error: function(xhr, status, err) {
|
||||
box.remove();
|
||||
navigator.id.logout();
|
||||
alert('Login failure: ' + err);
|
||||
}
|
||||
});
|
||||
},
|
||||
onlogout: function() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: $URL_ROOT + '_auth/logout',
|
||||
success: function(res, status, xhr) { window.location.reload(); },
|
||||
error: function(xhr, status, err) {
|
||||
alert('Logout failure: ' + err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
BIN
examples/persona/static/spinner.png
Normal file
BIN
examples/persona/static/spinner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
39
examples/persona/static/style.css
Normal file
39
examples/persona/static/style.css
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
html {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Verdana', sans-serif;
|
||||
font-size: 15px;
|
||||
margin: 30px auto;
|
||||
width: 720px;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1, h2, a {
|
||||
color: #d00;
|
||||
}
|
||||
|
||||
div.authbar {
|
||||
background: #eee;
|
||||
padding: 0 15px;
|
||||
margin: 10px -15px;
|
||||
line-height: 25px;
|
||||
height: 25px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.signinprogress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.8) url(spinner.png) center center no-repeat;
|
||||
font-size: 0;
|
||||
}
|
||||
23
examples/persona/templates/index.html
Normal file
23
examples/persona/templates/index.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block title %}Welcome{% endblock %}
|
||||
{% block body %}
|
||||
<h2>Welcome</h2>
|
||||
<p>
|
||||
This is a small example application that shows how to integrate
|
||||
Mozilla's persona signin service into a Flask application.
|
||||
<p>
|
||||
The advantage of persona over your own login system is that the
|
||||
password is managed outside of your application and you get
|
||||
a verified mail address as primary identifier for your user.
|
||||
<p>
|
||||
In this example nothing is actually stored on the server, it
|
||||
just takes over the email address from the persona verifier
|
||||
and stores it in a session.
|
||||
{% if g.user %}
|
||||
<p>
|
||||
You are now logged in as <strong>{{ g.user }}</strong>
|
||||
{% else %}
|
||||
<p>
|
||||
To sign in click the sign in button above.
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
27
examples/persona/templates/layout.html
Normal file
27
examples/persona/templates/layout.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<title>{% block title %}{% endblock %} | My Blog</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||
<script src="{{ config.PERSONA_JS }}"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
|
||||
<script>
|
||||
/* the url root is useful for doing HTTP requests */
|
||||
var $URL_ROOT = {{ request.url_root|tojson }};
|
||||
|
||||
/* we store the current user here so that the persona
|
||||
javascript support knows about the current user */
|
||||
var $CURRENT_USER = {{ g.user|tojson }};
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='persona.js') }}"></script>
|
||||
<link rel=stylesheet href="{{ url_for('static', filename='style.css') }}">
|
||||
<header>
|
||||
<h1>Mozilla Persona Example</h1>
|
||||
<div class=authbar>
|
||||
{% if g.user %}
|
||||
Signed in as <em>{{ g.user }}</em>
|
||||
(<a href="#" class=signout>Sign out</a>)
|
||||
{% else %}
|
||||
Not signed in. <a href="#" class=signin>Sign in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</header>
|
||||
{% block body %}{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue