mirror of
https://github.com/wassname/flask-security.git
synced 2026-08-07 11:22:21 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8fbd6cec8 | ||
|
|
9d11dd0787 | ||
|
|
3a5a1b4f52 | ||
|
|
0724bd12a5 | ||
|
|
c7e3e642fa | ||
|
|
ee4c8f2a3f | ||
|
|
1092ffc9ea | ||
|
|
f4b6eb9869 | ||
|
|
5e49a4e05b | ||
|
|
adc50f07eb | ||
|
|
874c758340 | ||
|
|
ed031f01ba | ||
|
|
4cbae25ac0 | ||
|
|
7f002ac612 | ||
|
|
9e8fcbc879 | ||
|
|
c8a24a8647 | ||
|
|
e83a970b3a | ||
|
|
514d27fd66 | ||
|
|
16976fce4e | ||
|
|
3dc2304d6e | ||
|
|
7a04a857f2 | ||
|
|
a107cd98db | ||
|
|
d7f52af371 |
@@ -3,6 +3,29 @@ Flask-Security Changelog
|
||||
|
||||
Here you can see the full list of changes between each Flask-Security release.
|
||||
|
||||
Version 1.5.3
|
||||
-------------
|
||||
|
||||
Released December 23rd 2012
|
||||
|
||||
- Change dependency requirement
|
||||
|
||||
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
|
||||
-------------
|
||||
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ copyright = u'2012, Matt Wright'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.5.0'
|
||||
version = '1.5.3'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
|
||||
@@ -129,6 +129,28 @@ Feature Flags
|
||||
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
|
||||
-------------
|
||||
|
||||
@@ -68,3 +68,33 @@ using SQLAlchemy.::
|
||||
|
||||
if __name__ == '__main__':
|
||||
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.
|
||||
"""
|
||||
|
||||
__version__ = '1.5.0'
|
||||
__version__ = '1.5.3'
|
||||
|
||||
from .core import Security, RoleMixin, UserMixin, AnonymousUser, current_user
|
||||
from .datastore import SQLAlchemyUserDatastore, MongoEngineUserDatastore
|
||||
|
||||
@@ -14,7 +14,8 @@ from datetime import datetime
|
||||
from flask import current_app as app, request
|
||||
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
|
||||
|
||||
|
||||
@@ -39,7 +40,7 @@ def send_confirmation_instructions(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_link=confirmation_link)
|
||||
|
||||
@@ -52,7 +53,7 @@ def generate_confirmation_token(user):
|
||||
|
||||
: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)
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,12 @@ _default_config = {
|
||||
'RESET_SALT': 'reset-salt',
|
||||
'LOGIN_SALT': 'login-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
|
||||
|
||||
@@ -56,8 +56,11 @@ class UserDatastore(object):
|
||||
self.role_model = role_model
|
||||
|
||||
def _prepare_role_modify_args(self, user, role):
|
||||
role = role.name if isinstance(role, self.role_model) else role
|
||||
return self.find_user(email=user.email), self.find_role(role)
|
||||
if isinstance(user, basestring):
|
||||
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):
|
||||
kwargs.setdefault('active', True)
|
||||
|
||||
@@ -13,7 +13,8 @@ from flask import request, current_app as app
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
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
|
||||
@@ -32,7 +33,7 @@ def send_login_instructions(user):
|
||||
url = url_for_security('token_login', token=token)
|
||||
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_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
|
||||
"""
|
||||
return _security.login_serializer.dumps([user.id])
|
||||
return _security.login_serializer.dumps([str(user.id)])
|
||||
|
||||
|
||||
def login_token_status(token):
|
||||
|
||||
@@ -14,7 +14,7 @@ from werkzeug.local import LocalProxy
|
||||
|
||||
from .signals import password_reset, reset_password_instructions_sent
|
||||
from .utils import send_mail, md5, encrypt_password, url_for_security, \
|
||||
get_token_status
|
||||
get_token_status, config_value
|
||||
|
||||
|
||||
# Convenient references
|
||||
@@ -32,7 +32,7 @@ def send_reset_password_instructions(user):
|
||||
url = url_for_security('reset_password', token=token)
|
||||
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',
|
||||
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
|
||||
"""
|
||||
send_mail('Your password has been reset', user.email,
|
||||
send_mail(config_value('EMAIL_SUBJECT_PASSWORD_NOTICE'), user.email,
|
||||
'reset_notice', user=user)
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ def generate_reset_password_token(user):
|
||||
|
||||
: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)
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ from werkzeug.local import LocalProxy
|
||||
|
||||
from .confirmable import generate_confirmation_link
|
||||
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
|
||||
_security = LocalProxy(lambda: app.extensions['security'])
|
||||
@@ -35,7 +36,7 @@ def register_user(**kwargs):
|
||||
user_registered.send(dict(user=user, confirm_token=token),
|
||||
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)
|
||||
|
||||
return user
|
||||
|
||||
+11
-9
@@ -38,23 +38,25 @@ _pwd_context = LocalProxy(lambda: _security.pwd_context)
|
||||
def login_user(user, remember=True):
|
||||
"""Performs the login and sends the appropriate signal."""
|
||||
|
||||
_login_user(user, remember)
|
||||
if not _login_user(user, remember):
|
||||
return False
|
||||
|
||||
if _security.trackable:
|
||||
old_current, new_current = user.current_login_at, datetime.utcnow()
|
||||
user.last_login_at = old_current or new_current
|
||||
user.current_login_at = new_current
|
||||
|
||||
old_current_login, new_current_login = user.current_login_at, datetime.utcnow()
|
||||
remote_addr = request.remote_addr or 'untrackable'
|
||||
old_current, new_current = user.current_login_ip, remote_addr
|
||||
user.last_login_ip = old_current or new_current
|
||||
user.current_login_ip = new_current
|
||||
old_current_ip, new_current_ip = user.current_login_ip, remote_addr
|
||||
|
||||
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
|
||||
|
||||
_datastore.put(user)
|
||||
_datastore.put(user)
|
||||
|
||||
identity_changed.send(current_app._get_current_object(),
|
||||
identity=Identity(user.id))
|
||||
return True
|
||||
|
||||
|
||||
def logout_user():
|
||||
|
||||
@@ -76,6 +76,9 @@ def login():
|
||||
if not request.json:
|
||||
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:
|
||||
return _render_json(form, True)
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ source-dir = docs/
|
||||
build-dir = docs/_build
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = docs/_build
|
||||
upload-dir = docs/_build/html
|
||||
@@ -20,7 +20,7 @@ from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='Flask-Security',
|
||||
version='1.5.0',
|
||||
version='1.5.3',
|
||||
url='https://github.com/mattupstate/flask-security',
|
||||
license='MIT',
|
||||
author='Matt Wright',
|
||||
@@ -35,12 +35,12 @@ setup(
|
||||
platforms='any',
|
||||
install_requires=[
|
||||
'Flask>=0.8',
|
||||
'Flask-Login==0.1.3',
|
||||
'Flask-Mail==0.7.3',
|
||||
'Flask-Principal==0.3.3',
|
||||
'Flask-WTF==0.8',
|
||||
'itsdangerous==0.17',
|
||||
'passlib==1.6.1',
|
||||
'Flask-Login>=0.1.3',
|
||||
'Flask-Mail>=0.7.3',
|
||||
'Flask-Principal>=0.3.3',
|
||||
'Flask-WTF>=0.8',
|
||||
'itsdangerous>=0.17',
|
||||
'passlib>=1.6.1',
|
||||
],
|
||||
test_suite='nose.collector',
|
||||
tests_require=[
|
||||
|
||||
@@ -121,6 +121,7 @@ class ConfirmableTests(SecurityTest):
|
||||
AUTH_CONFIG = {
|
||||
'SECURITY_CONFIRMABLE': True,
|
||||
'SECURITY_REGISTERABLE': True,
|
||||
'SECURITY_EMAIL_SUBJECT_REGISTER': 'Custom welcome subject',
|
||||
'USER_COUNT': 1
|
||||
}
|
||||
|
||||
@@ -148,6 +149,7 @@ class ConfirmableTests(SecurityTest):
|
||||
self.register(e)
|
||||
self.assertEqual(len(outbox), 1)
|
||||
self.assertIn(e, outbox[0].html)
|
||||
self.assertEqual('Custom welcome subject', outbox[0].subject)
|
||||
|
||||
def test_confirm_email(self):
|
||||
e = 'dude@lp.com'
|
||||
|
||||
Reference in New Issue
Block a user