Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
flask-admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Python-Dev
flask-admin
Commits
b5833775
Commit
b5833775
authored
May 24, 2015
by
Petrus J.v.Rensburg
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new 'auth' example, using Flask-Security.
parent
15581d05
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
141 additions
and
192 deletions
+141
-192
app.py
examples/auth/app.py
+87
-158
config.py
examples/auth/config.py
+25
-0
requirements.txt
examples/auth/requirements.txt
+1
-1
index.html
examples/auth/templates/admin/index.html
+21
-31
my_master.html
examples/auth/templates/my_master.html
+7
-2
No files found.
examples/auth/app.py
View file @
b5833775
import
os
import
os
from
flask
import
Flask
,
url_for
,
redirect
,
render_template
,
request
from
flask
import
Flask
,
url_for
,
redirect
,
render_template
,
request
,
abort
from
flask_sqlalchemy
import
SQLAlchemy
from
flask_sqlalchemy
import
SQLAlchemy
from
wtforms
import
form
,
fields
,
validators
from
flask_security
import
Security
,
SQLAlchemyUserDatastore
,
\
UserMixin
,
RoleMixin
,
login_required
,
current_user
from
flask_security.utils
import
encrypt_password
import
flask_admin
as
admin
import
flask_admin
as
admin
import
flask_login
as
login
from
flask_admin.contrib
import
sqla
from
flask_admin.contrib
import
sqla
from
flask_admin
import
helpers
,
expose
from
sqlalchemy
import
event
from
werkzeug.security
import
generate_password_hash
,
check_password_hash
# Create Flask application
# Create Flask application
app
=
Flask
(
__name__
)
app
=
Flask
(
__name__
)
app
.
config
.
from_pyfile
(
'config.py'
)
# Create dummy secrey key so we can use sessions
app
.
config
[
'SECRET_KEY'
]
=
'123456790'
# Create in-memory database
app
.
config
[
'DATABASE_FILE'
]
=
'sample_db.sqlite'
app
.
config
[
'SQLALCHEMY_DATABASE_URI'
]
=
'sqlite:///'
+
app
.
config
[
'DATABASE_FILE'
]
app
.
config
[
'SQLALCHEMY_ECHO'
]
=
True
db
=
SQLAlchemy
(
app
)
db
=
SQLAlchemy
(
app
)
# Create user model.
# Define models
class
User
(
db
.
Model
):
roles_users
=
db
.
Table
(
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
'roles_users'
,
first_name
=
db
.
Column
(
db
.
String
(
100
))
db
.
Column
(
'user_id'
,
db
.
Integer
(),
db
.
ForeignKey
(
'user.id'
)),
last_name
=
db
.
Column
(
db
.
String
(
100
))
db
.
Column
(
'role_id'
,
db
.
Integer
(),
db
.
ForeignKey
(
'role.id'
))
login
=
db
.
Column
(
db
.
String
(
80
),
unique
=
True
)
)
email
=
db
.
Column
(
db
.
String
(
120
))
password
=
db
.
Column
(
db
.
String
(
64
))
# Flask-Login integration
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
# Required for administrative interface
def
__unicode__
(
self
):
return
self
.
username
# Define login and registration forms (for flask-login)
class
LoginForm
(
form
.
Form
):
login
=
fields
.
TextField
(
validators
=
[
validators
.
required
()])
password
=
fields
.
PasswordField
(
validators
=
[
validators
.
required
()])
def
validate_login
(
self
,
field
):
user
=
self
.
get_user
()
if
user
is
None
:
raise
validators
.
ValidationError
(
'Invalid user'
)
# we're comparing the plaintext pw with the the hash from the db
if
not
check_password_hash
(
user
.
password
,
self
.
password
.
data
):
# to compare plain text passwords use
# if user.password != self.password.data:
raise
validators
.
ValidationError
(
'Invalid password'
)
def
get_user
(
self
):
return
db
.
session
.
query
(
User
)
.
filter_by
(
login
=
self
.
login
.
data
)
.
first
()
class
Role
(
db
.
Model
,
RoleMixin
):
id
=
db
.
Column
(
db
.
Integer
(),
primary_key
=
True
)
name
=
db
.
Column
(
db
.
String
(
80
),
unique
=
True
)
description
=
db
.
Column
(
db
.
String
(
255
))
class
RegistrationForm
(
form
.
Form
):
login
=
fields
.
TextField
(
validators
=
[
validators
.
required
()])
email
=
fields
.
TextField
()
password
=
fields
.
PasswordField
(
validators
=
[
validators
.
required
()])
def
validate_login
(
self
,
field
):
if
db
.
session
.
query
(
User
)
.
filter_by
(
login
=
self
.
login
.
data
)
.
count
()
>
0
:
raise
validators
.
ValidationError
(
'Duplicate username'
)
class
User
(
db
.
Model
,
UserMixin
):
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
first_name
=
db
.
Column
(
db
.
String
(
255
))
last_name
=
db
.
Column
(
db
.
String
(
255
))
email
=
db
.
Column
(
db
.
String
(
255
),
unique
=
True
)
password
=
db
.
Column
(
db
.
String
(
255
))
active
=
db
.
Column
(
db
.
Boolean
())
confirmed_at
=
db
.
Column
(
db
.
DateTime
())
roles
=
db
.
relationship
(
'Role'
,
secondary
=
roles_users
,
backref
=
db
.
backref
(
'users'
,
lazy
=
'dynamic'
))
# Initialize flask-login
def
init_login
():
login_manager
=
login
.
LoginManager
()
login_manager
.
init_app
(
app
)
# Create user loader function
# Setup Flask-Security
@
login_manager
.
user_loader
user_datastore
=
SQLAlchemyUserDatastore
(
db
,
User
,
Role
)
def
load_user
(
user_id
):
security
=
Security
(
app
,
user_datastore
)
return
db
.
session
.
query
(
User
)
.
get
(
user_id
)
# Create customized model view class
# Create customized model view class
class
MyModelView
(
sqla
.
ModelView
):
class
MyModelView
(
sqla
.
ModelView
):
def
is_accessible
(
self
):
def
is_accessible
(
self
):
return
login
.
current_user
.
is_authenticated
()
if
not
current_user
.
is_active
()
or
not
current_user
.
is_authenticated
():
return
False
# Create customized index view class that handles login & registration
class
MyAdminIndexView
(
admin
.
AdminIndexView
):
@
expose
(
'/'
)
def
index
(
self
):
if
not
login
.
current_user
.
is_authenticated
():
return
redirect
(
url_for
(
'.login_view'
))
return
super
(
MyAdminIndexView
,
self
)
.
index
()
@
expose
(
'/login/'
,
methods
=
(
'GET'
,
'POST'
))
def
login_view
(
self
):
# handle user login
form
=
LoginForm
(
request
.
form
)
if
helpers
.
validate_form_on_submit
(
form
):
user
=
form
.
get_user
()
login
.
login_user
(
user
)
if
login
.
current_user
.
is_authenticated
():
return
redirect
(
url_for
(
'.index'
))
link
=
'<p>Don
\'
t have an account? <a href="'
+
url_for
(
'.register_view'
)
+
'">Click here to register.</a></p>'
self
.
_template_args
[
'form'
]
=
form
self
.
_template_args
[
'link'
]
=
link
return
super
(
MyAdminIndexView
,
self
)
.
index
()
@
expose
(
'/register/'
,
methods
=
(
'GET'
,
'POST'
))
def
register_view
(
self
):
form
=
RegistrationForm
(
request
.
form
)
if
helpers
.
validate_form_on_submit
(
form
):
user
=
User
()
form
.
populate_obj
(
user
)
# we hash the users password to avoid saving it as plaintext in the db,
# remove to use plain text:
user
.
password
=
generate_password_hash
(
form
.
password
.
data
)
db
.
session
.
add
(
user
)
db
.
session
.
commit
()
login
.
login_user
(
user
)
if
current_user
.
has_role
(
'superuser'
):
return
redirect
(
url_for
(
'.index'
))
return
True
link
=
'<p>Already have an account? <a href="'
+
url_for
(
'.login_view'
)
+
'">Click here to log in.</a></p>'
self
.
_template_args
[
'form'
]
=
form
self
.
_template_args
[
'link'
]
=
link
return
super
(
MyAdminIndexView
,
self
)
.
index
()
@
expose
(
'/logout/'
)
return
False
def
logout_view
(
self
):
login
.
logout_user
()
return
redirect
(
url_for
(
'.index'
))
def
_handle_view
(
self
,
name
,
**
kwargs
):
"""
Override builtin _handle_view in order to redirect users when a view is not accessible.
"""
if
not
self
.
is_accessible
():
if
current_user
.
is_authenticated
():
# permission denied
abort
(
403
)
else
:
# login
return
redirect
(
url_for
(
'security.login'
,
next
=
request
.
url
))
# Flask views
# Flask views
@
app
.
route
(
'/'
)
@
app
.
route
(
'/'
)
def
index
():
def
index
():
return
render_template
(
'index.html'
)
return
render_template
(
'index.html'
)
# Initialize flask-login
init_login
()
# Create admin
# Create admin
admin
=
admin
.
Admin
(
app
,
'Example: Auth'
,
index_view
=
MyAdminIndexView
(),
base_template
=
'my_master.html'
)
admin
=
admin
.
Admin
(
app
,
'Example: Auth'
,
base_template
=
'my_master.html'
)
# Add view
# Add model views
admin
.
add_view
(
MyModelView
(
Role
,
db
.
session
))
admin
.
add_view
(
MyModelView
(
User
,
db
.
session
))
admin
.
add_view
(
MyModelView
(
User
,
db
.
session
))
...
@@ -175,13 +93,23 @@ def build_sample_db():
...
@@ -175,13 +93,23 @@ def build_sample_db():
db
.
drop_all
()
db
.
drop_all
()
db
.
create_all
()
db
.
create_all
()
# passwords are hashed, to use plaintext passwords instead:
# test_user = User(login="test", password="test")
with
app
.
app_context
():
test_user
=
User
(
login
=
"test"
,
password
=
generate_password_hash
(
"test"
))
user_role
=
Role
(
name
=
'user'
)
db
.
session
.
add
(
test_user
)
super_user_role
=
Role
(
name
=
'superuser'
)
db
.
session
.
add
(
user_role
)
db
.
session
.
add
(
super_user_role
)
db
.
session
.
commit
()
test_user
=
user_datastore
.
create_user
(
first_name
=
'Admin'
,
email
=
'admin'
,
password
=
encrypt_password
(
'admin'
),
roles
=
[
user_role
,
super_user_role
]
)
first_names
=
[
first_names
=
[
'Harry'
,
'Amelia'
,
'Oliver'
,
'Jack'
,
'Isabella'
,
'Charlie'
,
'Sophie'
,
'Mia'
,
'Harry'
,
'Amelia'
,
'Oliver'
,
'Jack'
,
'Isabella'
,
'Charlie'
,
'Sophie'
,
'Mia'
,
'Jacob'
,
'Thomas'
,
'Emily'
,
'Lily'
,
'Ava'
,
'Isla'
,
'Alfie'
,
'Olivia'
,
'Jessica'
,
'Jacob'
,
'Thomas'
,
'Emily'
,
'Lily'
,
'Ava'
,
'Isla'
,
'Alfie'
,
'Olivia'
,
'Jessica'
,
'Riley'
,
'William'
,
'James'
,
'Geoffrey'
,
'Lisa'
,
'Benjamin'
,
'Stacey'
,
'Lucy'
'Riley'
,
'William'
,
'James'
,
'Geoffrey'
,
'Lisa'
,
'Benjamin'
,
'Stacey'
,
'Lucy'
]
]
...
@@ -192,14 +120,15 @@ def build_sample_db():
...
@@ -192,14 +120,15 @@ def build_sample_db():
]
]
for
i
in
range
(
len
(
first_names
)):
for
i
in
range
(
len
(
first_names
)):
user
=
User
()
tmp_email
=
first_names
[
i
]
.
lower
()
+
"."
+
last_names
[
i
]
.
lower
()
+
"@example.com"
user
.
first_name
=
first_names
[
i
]
tmp_pass
=
''
.
join
(
random
.
choice
(
string
.
ascii_lowercase
+
string
.
digits
)
for
i
in
range
(
10
))
user
.
last_name
=
last_names
[
i
]
user_datastore
.
create_user
(
user
.
login
=
user
.
first_name
.
lower
()
first_name
=
first_names
[
i
],
user
.
email
=
user
.
login
+
"@example.com"
last_name
=
last_names
[
i
],
user
.
password
=
generate_password_hash
(
''
.
join
(
random
.
choice
(
string
.
ascii_lowercase
+
string
.
digits
)
for
i
in
range
(
10
)))
email
=
tmp_email
,
db
.
session
.
add
(
user
)
password
=
encrypt_password
(
tmp_pass
),
roles
=
[
user_role
,
]
)
db
.
session
.
commit
()
db
.
session
.
commit
()
return
return
...
...
examples/auth/config.py
0 → 100644
View file @
b5833775
# Create dummy secrey key so we can use sessions
SECRET_KEY
=
'123456790'
# Create in-memory database
DATABASE_FILE
=
'sample_db.sqlite'
SQLALCHEMY_DATABASE_URI
=
'sqlite:///'
+
DATABASE_FILE
SQLALCHEMY_ECHO
=
True
# Flask-Security config
SECURITY_URL_PREFIX
=
"/admin"
SECURITY_PASSWORD_HASH
=
"pbkdf2_sha512"
SECURITY_PASSWORD_SALT
=
"ATGUOHAELKiubahiughaerGOJAEGj"
# Flask-Security URLs, overridden because they don't put a / at the end
SECURITY_LOGIN_URL
=
"/login/"
SECURITY_LOGOUT_URL
=
"/logout/"
SECURITY_REGISTER_URL
=
"/register/"
SECURITY_POST_LOGIN_VIEW
=
"/admin/"
SECURITY_POST_LOGOUT_VIEW
=
"/admin/"
SECURITY_POST_REGISTER_VIEW
=
"/admin/"
# Flask-Security features
SECURITY_REGISTERABLE
=
True
SECURITY_SEND_REGISTER_EMAIL
=
False
\ No newline at end of file
examples/auth/requirements.txt
View file @
b5833775
Flask
Flask
Flask-Admin
Flask-Admin
Flask-SQLAlchemy
Flask-SQLAlchemy
Flask-
Login
Flask-
Security==1.7.4
\ No newline at end of file
examples/auth/templates/admin/index.html
View file @
b5833775
...
@@ -4,33 +4,23 @@
...
@@ -4,33 +4,23 @@
<div
class=
"row-fluid"
>
<div
class=
"row-fluid"
>
<div>
<div>
{% if current_user.is_authenticated() %}
<h1>
Flask-Admin example
</h1>
<h1>
Flask-Admin example
</h1>
<p
class=
"lead"
>
<p
class=
"lead"
>
Authentication
Authentication
</p>
</p>
<p>
<p>
This example shows how you can use Flask-Login for authentication. It is only intended as a basic demonstr
ation.
This example shows how you can use Flask-Security for authentic
ation.
</p>
</p>
{% else %}
{% if not current_user.is_authenticated() %}
<form
method=
"POST"
action=
""
>
<p>
You can register as a regular user, or log in as a superuser with the following credentials:
{{ form.hidden_tag() if form.hidden_tag }}
{% for f in form if f.type != 'CSRFTokenField' %}
<div>
{{ f.label }}
{{ f }}
{% if f.errors %}
<ul>
<ul>
{% for e in f.errors %}
<li>
email:
<b>
admin
</b></li>
<li>
{{ e }}
</li>
<li>
password:
<b>
admin
</b></li>
{% endfor %}
</ul>
</ul>
{% endif %}
</p>
</div>
<p>
{% endfor %}
<a
class=
"btn btn-default"
href=
"{{ url_for('security.login') }}"
>
login
</a>
<a
class=
"btn btn-default"
href=
"{{ url_for('security.register') }}"
>
register
</a>
<button
class=
"btn"
type=
"submit"
>
Submit
</button>
</p>
</form>
{{ link | safe }}
{% endif %}
{% endif %}
</div>
</div>
...
...
examples/auth/templates/my_master.html
View file @
b5833775
...
@@ -4,10 +4,15 @@
...
@@ -4,10 +4,15 @@
{% if current_user.is_authenticated() %}
{% if current_user.is_authenticated() %}
<div
class=
"btn-group pull-right"
>
<div
class=
"btn-group pull-right"
>
<a
class=
"btn dropdown-toggle"
data-toggle=
"dropdown"
href=
"#"
>
<a
class=
"btn dropdown-toggle"
data-toggle=
"dropdown"
href=
"#"
>
<i
class=
"icon-user"
></i>
{{ current_user.login }}
<span
class=
"caret"
></span>
<i
class=
"icon-user"
></i>
{% if current_user.first_name -%}
{{ current_user.first_name }}
{% else -%}
{{ current_user.email }}
{%- endif %}
<span
class=
"caret"
></span>
</a>
</a>
<ul
class=
"dropdown-menu"
>
<ul
class=
"dropdown-menu"
>
<li><a
href=
"{{ url_for('
admin.logout_view
') }}"
>
Log out
</a></li>
<li><a
href=
"{{ url_for('
security.logout
') }}"
>
Log out
</a></li>
</ul>
</ul>
</div>
</div>
{% endif %}
{% endif %}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment