mirror of
https://github.com/wassname/flask-security.git
synced 2026-08-07 11:22:21 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a5a1b4f52 | ||
|
|
0724bd12a5 | ||
|
|
c7e3e642fa | ||
|
|
ee4c8f2a3f | ||
|
|
1092ffc9ea | ||
|
|
f4b6eb9869 | ||
|
|
5e49a4e05b | ||
|
|
adc50f07eb | ||
|
|
874c758340 | ||
|
|
ed031f01ba | ||
|
|
4cbae25ac0 | ||
|
|
7f002ac612 | ||
|
|
9e8fcbc879 | ||
|
|
c8a24a8647 | ||
|
|
e83a970b3a | ||
|
|
514d27fd66 | ||
|
|
16976fce4e | ||
|
|
3dc2304d6e | ||
|
|
7a04a857f2 | ||
|
|
a107cd98db | ||
|
|
d7f52af371 |
@@ -3,6 +3,22 @@ Flask-Security Changelog
|
|||||||
|
|
||||||
Here you can see the full list of changes between each Flask-Security release.
|
Here you can see the full list of changes between each Flask-Security release.
|
||||||
|
|
||||||
|
Version 1.5.2
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Released December 11th 2012
|
||||||
|
|
||||||
|
- Fix a small bug in `flask_security.utils.login_user` method
|
||||||
|
|
||||||
|
Version 1.5.1
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Released November 26th 2012
|
||||||
|
|
||||||
|
- Fixed bug with `next` form variable
|
||||||
|
- Added better documentation regarding Flask-Mail configuration
|
||||||
|
- Added ability to configure email subjects
|
||||||
|
|
||||||
Version 1.5.0
|
Version 1.5.0
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ copyright = u'2012, Matt Wright'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.5.0'
|
version = '1.5.2'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = version
|
release = version
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,28 @@ Feature Flags
|
|||||||
to ``False``.
|
to ``False``.
|
||||||
========================= ======================================================
|
========================= ======================================================
|
||||||
|
|
||||||
|
Email
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.5cm}|p{8.5cm}|
|
||||||
|
|
||||||
|
=========================================== ====================================
|
||||||
|
``SECURITY_EMAIL_SUBJECT_REGISTER`` Sets the subject for the
|
||||||
|
confirmation email. Defaults to
|
||||||
|
``Welcome``
|
||||||
|
``SECURITY_EMAIL_SUBJECT_PASSWORDLESS`` Sets the subject for the
|
||||||
|
passwordless feature. Defaults to
|
||||||
|
``Login instructions``
|
||||||
|
``SECURITY_EMAIL_SUBJECT_PASSWORD_NOTICE`` Sets subject for the password
|
||||||
|
notice. Defaults to
|
||||||
|
``Your password has been reset``
|
||||||
|
``SECURITY_EMAIL_SUBJECT_PASSWORD_RESET`` Sets the subject for the password
|
||||||
|
reset. Defaults to
|
||||||
|
``Password reset instructions``
|
||||||
|
``SECURITY_EMAIL_SUBJECT_CONFIRM`` Sets the subject for the email
|
||||||
|
confirmation message. Defaults to
|
||||||
|
``Please confirm your email``
|
||||||
|
=========================================== ====================================
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -68,3 +68,33 @@ using SQLAlchemy.::
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
|
Mail Configuration
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Flask-Security integrates with Flask-Mail to handle all email communications
|
||||||
|
between user and site, so it's important to configure Flask-Mail with your
|
||||||
|
email server details so Flask-Security can talk with Flask-Mail correctly.
|
||||||
|
|
||||||
|
The following code illustrates a basic setup, which could be added to the
|
||||||
|
basic application code in the previous section::
|
||||||
|
|
||||||
|
# At top of file
|
||||||
|
from flask_mail import Mail
|
||||||
|
|
||||||
|
# After 'Create app'
|
||||||
|
app.config['MAIL_SERVER'] = 'smtp.example.com'
|
||||||
|
app.config['MAIL_PORT'] = 465
|
||||||
|
app.config['MAIL_USE_SSL'] = True
|
||||||
|
app.config['MAIL_USERNAME'] = 'username'
|
||||||
|
app.config['MAIL_PASSWORD'] = 'password'
|
||||||
|
mail = Mail(app)
|
||||||
|
|
||||||
|
To learn more about the various Flask-Mail settings to configure it to work
|
||||||
|
with your particular email server configuration, please see the
|
||||||
|
`Flask-Mail documentation <http://packages.python.org/Flask-Mail/>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
:license: MIT, see LICENSE for more details.
|
:license: MIT, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '1.5.0'
|
__version__ = '1.5.2'
|
||||||
|
|
||||||
from .core import Security, RoleMixin, UserMixin, AnonymousUser, current_user
|
from .core import Security, RoleMixin, UserMixin, AnonymousUser, current_user
|
||||||
from .datastore import SQLAlchemyUserDatastore, MongoEngineUserDatastore
|
from .datastore import SQLAlchemyUserDatastore, MongoEngineUserDatastore
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from datetime import datetime
|
|||||||
from flask import current_app as app, request
|
from flask import current_app as app, request
|
||||||
from werkzeug.local import LocalProxy
|
from werkzeug.local import LocalProxy
|
||||||
|
|
||||||
from .utils import send_mail, md5, url_for_security, get_token_status
|
from .utils import send_mail, md5, url_for_security, get_token_status,\
|
||||||
|
config_value
|
||||||
from .signals import user_confirmed, confirm_instructions_sent
|
from .signals import user_confirmed, confirm_instructions_sent
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ def send_confirmation_instructions(user):
|
|||||||
|
|
||||||
confirmation_link, token = generate_confirmation_link(user)
|
confirmation_link, token = generate_confirmation_link(user)
|
||||||
|
|
||||||
send_mail('Please confirm your email', user.email,
|
send_mail(config_value('EMAIL_SUBJECT_CONFIRM'), user.email,
|
||||||
'confirmation_instructions', user=user,
|
'confirmation_instructions', user=user,
|
||||||
confirmation_link=confirmation_link)
|
confirmation_link=confirmation_link)
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ def generate_confirmation_token(user):
|
|||||||
|
|
||||||
:param user: The user to work with
|
:param user: The user to work with
|
||||||
"""
|
"""
|
||||||
data = [user.id, md5(user.email)]
|
data = [str(user.id), md5(user.email)]
|
||||||
return _security.confirm_serializer.dumps(data)
|
return _security.confirm_serializer.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,12 @@ _default_config = {
|
|||||||
'RESET_SALT': 'reset-salt',
|
'RESET_SALT': 'reset-salt',
|
||||||
'LOGIN_SALT': 'login-salt',
|
'LOGIN_SALT': 'login-salt',
|
||||||
'REMEMBER_SALT': 'remember-salt',
|
'REMEMBER_SALT': 'remember-salt',
|
||||||
'DEFAULT_HTTP_AUTH_REALM': 'Login Required'
|
'DEFAULT_HTTP_AUTH_REALM': 'Login Required',
|
||||||
|
'EMAIL_SUBJECT_REGISTER': 'Welcome',
|
||||||
|
'EMAIL_SUBJECT_CONFIRM': 'Please confirm your email',
|
||||||
|
'EMAIL_SUBJECT_PASSWORDLESS': 'Login instructions',
|
||||||
|
'EMAIL_SUBJECT_PASSWORD_NOTICE': 'Your password has been reset',
|
||||||
|
'EMAIL_SUBJECT_PASSWORD_RESET': 'Password reset instructions'
|
||||||
}
|
}
|
||||||
|
|
||||||
#: Default Flask-Security messages
|
#: Default Flask-Security messages
|
||||||
|
|||||||
@@ -56,8 +56,11 @@ class UserDatastore(object):
|
|||||||
self.role_model = role_model
|
self.role_model = role_model
|
||||||
|
|
||||||
def _prepare_role_modify_args(self, user, role):
|
def _prepare_role_modify_args(self, user, role):
|
||||||
role = role.name if isinstance(role, self.role_model) else role
|
if isinstance(user, basestring):
|
||||||
return self.find_user(email=user.email), self.find_role(role)
|
user = self.find_user(email=user.email)
|
||||||
|
if isinstance(role, basestring):
|
||||||
|
role = self.find_role(role)
|
||||||
|
return user, role
|
||||||
|
|
||||||
def _prepare_create_user_args(self, **kwargs):
|
def _prepare_create_user_args(self, **kwargs):
|
||||||
kwargs.setdefault('active', True)
|
kwargs.setdefault('active', True)
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ from flask import request, current_app as app
|
|||||||
from werkzeug.local import LocalProxy
|
from werkzeug.local import LocalProxy
|
||||||
|
|
||||||
from .signals import login_instructions_sent
|
from .signals import login_instructions_sent
|
||||||
from .utils import send_mail, url_for_security, get_token_status
|
from .utils import send_mail, url_for_security, get_token_status, \
|
||||||
|
config_value
|
||||||
|
|
||||||
|
|
||||||
# Convenient references
|
# Convenient references
|
||||||
@@ -32,7 +33,7 @@ def send_login_instructions(user):
|
|||||||
url = url_for_security('token_login', token=token)
|
url = url_for_security('token_login', token=token)
|
||||||
login_link = request.url_root[:-1] + url
|
login_link = request.url_root[:-1] + url
|
||||||
|
|
||||||
send_mail('Login Instructions', user.email,
|
send_mail(config_value('EMAIL_SUBJECT_PASSWORDLESS'), user.email,
|
||||||
'login_instructions', user=user, login_link=login_link)
|
'login_instructions', user=user, login_link=login_link)
|
||||||
|
|
||||||
login_instructions_sent.send(dict(user=user, login_token=token),
|
login_instructions_sent.send(dict(user=user, login_token=token),
|
||||||
@@ -44,7 +45,7 @@ def generate_login_token(user):
|
|||||||
|
|
||||||
:param user: The user the token belongs to
|
:param user: The user the token belongs to
|
||||||
"""
|
"""
|
||||||
return _security.login_serializer.dumps([user.id])
|
return _security.login_serializer.dumps([str(user.id)])
|
||||||
|
|
||||||
|
|
||||||
def login_token_status(token):
|
def login_token_status(token):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from werkzeug.local import LocalProxy
|
|||||||
|
|
||||||
from .signals import password_reset, reset_password_instructions_sent
|
from .signals import password_reset, reset_password_instructions_sent
|
||||||
from .utils import send_mail, md5, encrypt_password, url_for_security, \
|
from .utils import send_mail, md5, encrypt_password, url_for_security, \
|
||||||
get_token_status
|
get_token_status, config_value
|
||||||
|
|
||||||
|
|
||||||
# Convenient references
|
# Convenient references
|
||||||
@@ -32,7 +32,7 @@ def send_reset_password_instructions(user):
|
|||||||
url = url_for_security('reset_password', token=token)
|
url = url_for_security('reset_password', token=token)
|
||||||
reset_link = request.url_root[:-1] + url
|
reset_link = request.url_root[:-1] + url
|
||||||
|
|
||||||
send_mail('Password reset instructions', user.email,
|
send_mail(config_value('EMAIL_SUBJECT_PASSWORD_RESET'), user.email,
|
||||||
'reset_instructions',
|
'reset_instructions',
|
||||||
user=user, reset_link=reset_link)
|
user=user, reset_link=reset_link)
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ def send_password_reset_notice(user):
|
|||||||
|
|
||||||
:param user: The user to send the notice to
|
:param user: The user to send the notice to
|
||||||
"""
|
"""
|
||||||
send_mail('Your password has been reset', user.email,
|
send_mail(config_value('EMAIL_SUBJECT_PASSWORD_NOTICE'), user.email,
|
||||||
'reset_notice', user=user)
|
'reset_notice', user=user)
|
||||||
|
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ def generate_reset_password_token(user):
|
|||||||
|
|
||||||
:param user: The user to work with
|
:param user: The user to work with
|
||||||
"""
|
"""
|
||||||
data = [user.id, md5(user.password)]
|
data = [str(user.id), md5(user.password)]
|
||||||
return _security.reset_serializer.dumps(data)
|
return _security.reset_serializer.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from werkzeug.local import LocalProxy
|
|||||||
|
|
||||||
from .confirmable import generate_confirmation_link
|
from .confirmable import generate_confirmation_link
|
||||||
from .signals import user_registered
|
from .signals import user_registered
|
||||||
from .utils import do_flash, get_message, send_mail, encrypt_password
|
from .utils import do_flash, get_message, send_mail, encrypt_password, \
|
||||||
|
config_value
|
||||||
|
|
||||||
# Convenient references
|
# Convenient references
|
||||||
_security = LocalProxy(lambda: app.extensions['security'])
|
_security = LocalProxy(lambda: app.extensions['security'])
|
||||||
@@ -35,7 +36,7 @@ def register_user(**kwargs):
|
|||||||
user_registered.send(dict(user=user, confirm_token=token),
|
user_registered.send(dict(user=user, confirm_token=token),
|
||||||
app=app._get_current_object())
|
app=app._get_current_object())
|
||||||
|
|
||||||
send_mail('Welcome', user.email, 'welcome',
|
send_mail(config_value('EMAIL_SUBJECT_REGISTER'), user.email, 'welcome',
|
||||||
user=user, confirmation_link=confirmation_link)
|
user=user, confirmation_link=confirmation_link)
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|||||||
+11
-9
@@ -38,23 +38,25 @@ _pwd_context = LocalProxy(lambda: _security.pwd_context)
|
|||||||
def login_user(user, remember=True):
|
def login_user(user, remember=True):
|
||||||
"""Performs the login and sends the appropriate signal."""
|
"""Performs the login and sends the appropriate signal."""
|
||||||
|
|
||||||
_login_user(user, remember)
|
if not _login_user(user, remember):
|
||||||
|
return False
|
||||||
|
|
||||||
if _security.trackable:
|
if _security.trackable:
|
||||||
old_current, new_current = user.current_login_at, datetime.utcnow()
|
old_current_login, new_current_login = user.current_login_at, datetime.utcnow()
|
||||||
user.last_login_at = old_current or new_current
|
|
||||||
user.current_login_at = new_current
|
|
||||||
|
|
||||||
remote_addr = request.remote_addr or 'untrackable'
|
remote_addr = request.remote_addr or 'untrackable'
|
||||||
old_current, new_current = user.current_login_ip, remote_addr
|
old_current_ip, new_current_ip = user.current_login_ip, remote_addr
|
||||||
user.last_login_ip = old_current or new_current
|
|
||||||
user.current_login_ip = new_current
|
|
||||||
|
|
||||||
|
user.last_login_at = old_current_login or new_current_login
|
||||||
|
user.current_login_at = new_current_login
|
||||||
|
user.last_login_ip = old_current_ip or new_current_ip
|
||||||
|
user.current_login_ip = new_current_ip
|
||||||
user.login_count = user.login_count + 1 if user.login_count else 1
|
user.login_count = user.login_count + 1 if user.login_count else 1
|
||||||
|
|
||||||
_datastore.put(user)
|
_datastore.put(user)
|
||||||
|
|
||||||
identity_changed.send(current_app._get_current_object(),
|
identity_changed.send(current_app._get_current_object(),
|
||||||
identity=Identity(user.id))
|
identity=Identity(user.id))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def logout_user():
|
def logout_user():
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ def login():
|
|||||||
if not request.json:
|
if not request.json:
|
||||||
return redirect(get_post_login_redirect())
|
return redirect(get_post_login_redirect())
|
||||||
|
|
||||||
|
form.next.data = get_url(request.args.get('next')) \
|
||||||
|
or get_url(request.form.get('next')) or ''
|
||||||
|
|
||||||
if request.json:
|
if request.json:
|
||||||
return _render_json(form, True)
|
return _render_json(form, True)
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ source-dir = docs/
|
|||||||
build-dir = docs/_build
|
build-dir = docs/_build
|
||||||
|
|
||||||
[upload_sphinx]
|
[upload_sphinx]
|
||||||
upload-dir = docs/_build
|
upload-dir = docs/_build/html
|
||||||
@@ -20,7 +20,7 @@ from setuptools import setup
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='Flask-Security',
|
name='Flask-Security',
|
||||||
version='1.5.0',
|
version='1.5.2',
|
||||||
url='https://github.com/mattupstate/flask-security',
|
url='https://github.com/mattupstate/flask-security',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
author='Matt Wright',
|
author='Matt Wright',
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ class ConfirmableTests(SecurityTest):
|
|||||||
AUTH_CONFIG = {
|
AUTH_CONFIG = {
|
||||||
'SECURITY_CONFIRMABLE': True,
|
'SECURITY_CONFIRMABLE': True,
|
||||||
'SECURITY_REGISTERABLE': True,
|
'SECURITY_REGISTERABLE': True,
|
||||||
|
'SECURITY_EMAIL_SUBJECT_REGISTER': 'Custom welcome subject',
|
||||||
'USER_COUNT': 1
|
'USER_COUNT': 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +149,7 @@ class ConfirmableTests(SecurityTest):
|
|||||||
self.register(e)
|
self.register(e)
|
||||||
self.assertEqual(len(outbox), 1)
|
self.assertEqual(len(outbox), 1)
|
||||||
self.assertIn(e, outbox[0].html)
|
self.assertIn(e, outbox[0].html)
|
||||||
|
self.assertEqual('Custom welcome subject', outbox[0].subject)
|
||||||
|
|
||||||
def test_confirm_email(self):
|
def test_confirm_email(self):
|
||||||
e = 'dude@lp.com'
|
e = 'dude@lp.com'
|
||||||
|
|||||||
Reference in New Issue
Block a user