mirror of
https://github.com/wassname/flask-security.git
synced 2026-07-11 00:40:08 +08:00
Code cleanup
This commit is contained in:
@@ -20,6 +20,5 @@ from .decorators import auth_token_required, http_auth_required, \
|
||||
from .forms import ForgotPasswordForm, LoginForm, RegisterForm, \
|
||||
ResetPasswordForm, PasswordlessLoginForm
|
||||
from .signals import confirm_instructions_sent, password_reset, \
|
||||
password_reset_requested, reset_instructions_sent, user_confirmed, \
|
||||
user_registered
|
||||
reset_password_instructions_sent, user_confirmed, user_registered
|
||||
from .utils import login_user, logout_user, url_for_security
|
||||
|
||||
@@ -26,12 +26,13 @@ _security = LocalProxy(lambda: app.extensions['security'])
|
||||
_datastore = LocalProxy(lambda: _security.datastore)
|
||||
|
||||
|
||||
def send_confirmation_instructions(user, token):
|
||||
def send_confirmation_instructions(user):
|
||||
"""Sends the confirmation instructions email for the specified user.
|
||||
|
||||
:param user: The user to send the instructions to
|
||||
:param token: The confirmation token
|
||||
"""
|
||||
token = generate_confirmation_token(user)
|
||||
url = url_for_security('confirm_email', token=token)
|
||||
|
||||
confirmation_link = request.url_root[:-1] + url
|
||||
@@ -43,6 +44,8 @@ def send_confirmation_instructions(user, token):
|
||||
|
||||
confirm_instructions_sent.send(user, app=app._get_current_object())
|
||||
|
||||
return token
|
||||
|
||||
|
||||
def generate_confirmation_token(user):
|
||||
"""Generates a unique confirmation token for the specified user.
|
||||
@@ -92,19 +95,3 @@ def confirm_by_token(token):
|
||||
|
||||
except BadSignature:
|
||||
raise ConfirmationError(get_message('INVALID_CONFIRMATION_TOKEN')[0])
|
||||
|
||||
|
||||
def reset_confirmation_token(user):
|
||||
"""Resets the specified user's confirmation token and sends the user
|
||||
an email with instructions explaining next steps.
|
||||
|
||||
:param user: The user to work with
|
||||
"""
|
||||
token = generate_confirmation_token(user)
|
||||
|
||||
user.confirmed_at = None
|
||||
_datastore._save_model(user)
|
||||
|
||||
send_confirmation_instructions(user, token)
|
||||
|
||||
return token
|
||||
|
||||
@@ -49,7 +49,6 @@ _default_config = {
|
||||
'POST_REGISTER_VIEW': None,
|
||||
'POST_CONFIRM_VIEW': None,
|
||||
'POST_RESET_VIEW': None,
|
||||
'RESET_PASSWORD_ERROR_VIEW': None,
|
||||
'UNAUTHORIZED_VIEW': None,
|
||||
'DEFAULT_ROLES': [],
|
||||
'CONFIRMABLE': False,
|
||||
|
||||
@@ -16,7 +16,7 @@ from werkzeug.local import LocalProxy
|
||||
from .exceptions import PasswordlessLoginError
|
||||
from .signals import login_instructions_sent
|
||||
from .utils import send_mail, md5, get_max_age, login_user, get_message, \
|
||||
url_for_security
|
||||
url_for_security, get_url
|
||||
|
||||
|
||||
# Convenient references
|
||||
@@ -47,6 +47,7 @@ def send_login_instructions(user, next):
|
||||
|
||||
|
||||
def generate_login_token(user, next):
|
||||
next = next or get_url(_security.post_login_view)
|
||||
data = [user.id, md5(user.password), next]
|
||||
return _security.login_serializer.dumps(data)
|
||||
|
||||
@@ -56,20 +57,19 @@ def login_by_token(token):
|
||||
max_age = get_max_age('LOGIN')
|
||||
|
||||
try:
|
||||
data = serializer.loads(token, max_age=max_age)
|
||||
user = _datastore.find_user(id=data[0])
|
||||
|
||||
user_id, pw, next = serializer.loads(token, max_age=max_age)
|
||||
user = _datastore.find_user(id=user_id)
|
||||
login_user(user, True)
|
||||
|
||||
return user, data[2]
|
||||
return user, next
|
||||
|
||||
except SignatureExpired:
|
||||
sig_okay, data = serializer.loads_unsafe(token)
|
||||
user_id, pw, next = data
|
||||
user = _datastore.find_user(id=data[0])
|
||||
msg = get_message('LOGIN_EXPIRED',
|
||||
within=_security.login_within,
|
||||
email=user.email)[0]
|
||||
raise PasswordlessLoginError(msg, user=user, next=data[2])
|
||||
within = _security.login_within
|
||||
msg = get_message('LOGIN_EXPIRED', within=within, email=user.email)
|
||||
raise PasswordlessLoginError(msg[0], user=user, next=next)
|
||||
|
||||
except BadSignature:
|
||||
raise PasswordlessLoginError(get_message('INVALID_LOGIN_TOKEN')[0])
|
||||
msg = get_message('INVALID_LOGIN_TOKEN')
|
||||
raise PasswordlessLoginError(msg[0])
|
||||
|
||||
@@ -13,9 +13,8 @@ from itsdangerous import BadSignature, SignatureExpired
|
||||
from flask import current_app as app, request
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
from .exceptions import ResetPasswordError, UserNotFoundError
|
||||
from .signals import password_reset, password_reset_requested, \
|
||||
reset_instructions_sent
|
||||
from .exceptions import ResetPasswordError
|
||||
from .signals import password_reset, reset_password_instructions_sent
|
||||
from .utils import send_mail, get_max_age, md5, get_message, encrypt_password, \
|
||||
url_for_security
|
||||
|
||||
@@ -26,12 +25,13 @@ _security = LocalProxy(lambda: app.extensions['security'])
|
||||
_datastore = LocalProxy(lambda: _security.datastore)
|
||||
|
||||
|
||||
def send_reset_password_instructions(user, reset_token):
|
||||
def send_reset_password_instructions(user):
|
||||
"""Sends the reset password instructions email for the specified user.
|
||||
|
||||
:param user: The user to send the instructions to
|
||||
"""
|
||||
url = url_for_security('reset_password', token=reset_token)
|
||||
token = generate_reset_password_token(user)
|
||||
url = url_for_security('reset_password', token=token)
|
||||
|
||||
reset_link = request.url_root[:-1] + url
|
||||
|
||||
@@ -40,8 +40,8 @@ def send_reset_password_instructions(user, reset_token):
|
||||
'reset_instructions',
|
||||
dict(user=user, reset_link=reset_link))
|
||||
|
||||
reset_instructions_sent.send(dict(user=user, token=reset_token),
|
||||
app=app._get_current_object())
|
||||
reset_password_instructions_sent.send(dict(user=user, token=token),
|
||||
app=app._get_current_object())
|
||||
|
||||
|
||||
def send_password_reset_notice(user):
|
||||
@@ -99,19 +99,3 @@ def reset_by_token(token, password):
|
||||
|
||||
except BadSignature:
|
||||
raise ResetPasswordError(get_message('INVALID_RESET_PASSWORD_TOKEN')[0])
|
||||
|
||||
|
||||
def reset_password_reset_token(user):
|
||||
"""Resets the specified user's reset password token and sends the user
|
||||
an email with instructions explaining next steps.
|
||||
|
||||
:param user: The user to work with
|
||||
"""
|
||||
token = generate_reset_password_token(user)
|
||||
|
||||
send_reset_password_instructions(user, token)
|
||||
|
||||
password_reset_requested.send(dict(user=user, token=token),
|
||||
app=app._get_current_object())
|
||||
|
||||
return token
|
||||
|
||||
@@ -24,6 +24,4 @@ login_instructions_sent = signals.signal("login-instructions-sent")
|
||||
|
||||
password_reset = signals.signal("password-reset")
|
||||
|
||||
password_reset_requested = signals.signal("password-reset-requested")
|
||||
|
||||
reset_instructions_sent = signals.signal("reset-instructions-sent")
|
||||
reset_password_instructions_sent = signals.signal("password-reset-instructions-sent")
|
||||
|
||||
@@ -24,7 +24,7 @@ from flask.ext.principal import Identity, AnonymousIdentity, identity_changed
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
from .core import current_user
|
||||
from .signals import user_registered, password_reset_requested, \
|
||||
from .signals import user_registered, reset_password_instructions_sent, \
|
||||
login_instructions_sent
|
||||
|
||||
|
||||
@@ -292,9 +292,9 @@ def capture_reset_password_requests(reset_password_sent_at=None):
|
||||
def _on(request, app):
|
||||
reset_requests.append(request)
|
||||
|
||||
password_reset_requested.connect(_on)
|
||||
reset_password_instructions_sent.connect(_on)
|
||||
|
||||
try:
|
||||
yield reset_requests
|
||||
finally:
|
||||
password_reset_requested.disconnect(_on)
|
||||
reset_password_instructions_sent.disconnect(_on)
|
||||
|
||||
+90
-108
@@ -14,7 +14,8 @@ from flask import current_app as app, redirect, request, \
|
||||
from werkzeug.datastructures import MultiDict
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
from flask_security.confirmable import confirm_by_token, reset_confirmation_token
|
||||
from flask_security.confirmable import confirm_by_token, \
|
||||
send_confirmation_instructions
|
||||
from flask_security.decorators import login_required
|
||||
from flask_security.exceptions import ConfirmationError, BadCredentialsError, \
|
||||
ResetPasswordError, PasswordlessLoginError
|
||||
@@ -22,11 +23,11 @@ from flask_security.forms import LoginForm, RegisterForm, ForgotPasswordForm, \
|
||||
ResetPasswordForm, SendConfirmationForm, PasswordlessLoginForm
|
||||
from flask_security.passwordless import send_login_instructions, login_by_token
|
||||
from flask_security.recoverable import reset_by_token, \
|
||||
reset_password_reset_token
|
||||
send_reset_password_instructions
|
||||
from flask_security.signals import user_registered
|
||||
from flask_security.utils import get_url, get_post_login_redirect, do_flash, \
|
||||
get_message, config_value, login_user, logout_user, url_for_security, \
|
||||
anonymous_user_required
|
||||
get_message, config_value, login_user, logout_user, \
|
||||
anonymous_user_required, url_for_security as url_for
|
||||
|
||||
|
||||
# Convenient references
|
||||
@@ -64,55 +65,61 @@ def _json_auth_error(msg):
|
||||
return resp
|
||||
|
||||
|
||||
def _commit_data(response=None):
|
||||
def _commit(response=None):
|
||||
_datastore._commit()
|
||||
return response
|
||||
|
||||
|
||||
def _ctx(endpoint):
|
||||
return _security._run_ctx_processor(endpoint)
|
||||
|
||||
|
||||
def authenticate():
|
||||
"""View function which handles an authentication request."""
|
||||
confirm_url = None
|
||||
form_data = MultiDict(request.json) if request.json else request.form
|
||||
form = LoginForm(form_data)
|
||||
|
||||
after_this_request(_commit_data)
|
||||
form = LoginForm(request.form)
|
||||
user, msg, confirm_url = None, None, None
|
||||
|
||||
if request.json:
|
||||
form = LoginForm(MultiDict(request.json))
|
||||
|
||||
try:
|
||||
user = _security.auth_provider.authenticate(form)
|
||||
|
||||
if login_user(user, remember=form.remember.data):
|
||||
if request.json:
|
||||
return _json_auth_ok(user)
|
||||
|
||||
return redirect(get_post_login_redirect())
|
||||
|
||||
raise BadCredentialsError(get_message('DISABLED_ACCOUNT')[0])
|
||||
|
||||
except ConfirmationError, e:
|
||||
msg = str(e)
|
||||
confirm_url = url_for_security('send_confirmation', email=e.user.email)
|
||||
|
||||
confirm_url = url_for('send_confirmation', email=e.user.email)
|
||||
except BadCredentialsError, e:
|
||||
msg = str(e)
|
||||
|
||||
if user:
|
||||
if login_user(user, remember=form.remember.data):
|
||||
after_this_request(_commit)
|
||||
if request.json:
|
||||
return _json_auth_ok(user)
|
||||
return redirect(get_post_login_redirect())
|
||||
msg = get_message('DISABLED_ACCOUNT')[0]
|
||||
|
||||
_logger.debug('Unsuccessful authentication attempt: %s' % msg)
|
||||
|
||||
if request.json:
|
||||
return _json_auth_error(msg)
|
||||
|
||||
do_flash(msg, 'error')
|
||||
|
||||
return redirect(confirm_url or url_for_security('login'))
|
||||
return redirect(confirm_url or url_for('login'))
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
def login():
|
||||
"""View function for login view"""
|
||||
|
||||
form = PasswordlessLoginForm() if _security.passwordless else LoginForm()
|
||||
template = 'send_login' if _security.passwordless else 'login'
|
||||
return render_template('security/%s.html' % template, login_form=form,
|
||||
**_security._run_ctx_processor('login'))
|
||||
tmp, form = '', LoginForm
|
||||
|
||||
if _security.passwordless:
|
||||
tmp, form = 'send_', PasswordlessLoginForm
|
||||
|
||||
return render_template('security/%slogin.html' % tmp,
|
||||
login_form=form(),
|
||||
**_ctx('login'))
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -120,11 +127,10 @@ def logout():
|
||||
"""View function which handles a logout request."""
|
||||
|
||||
logout_user()
|
||||
|
||||
_logger.debug('User logged out')
|
||||
|
||||
return redirect(request.args.get('next', None) or
|
||||
get_url(_security.post_logout_view))
|
||||
next_url = request.args.get('next', None)
|
||||
post_logout_url = get_url(_security.post_logout_view)
|
||||
return redirect(next_url or post_logout_url)
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
@@ -133,51 +139,51 @@ def register():
|
||||
|
||||
form = RegisterForm(csrf_enabled=not app.testing)
|
||||
|
||||
if form.validate_on_submit():
|
||||
# Create user
|
||||
u = _datastore.create_user(**form.to_dict())
|
||||
if not form.validate_on_submit():
|
||||
return render_template('security/register.html',
|
||||
register_user_form=form,
|
||||
**_ctx('register'))
|
||||
|
||||
# Save the user so the ID is created
|
||||
_commit_data()
|
||||
token = None
|
||||
user = _datastore.create_user(**form.to_dict())
|
||||
_commit()
|
||||
|
||||
# Send confirmation instructions if necessary
|
||||
t = reset_confirmation_token(u) if _security.confirmable else None
|
||||
if _security.confirmable:
|
||||
token = send_confirmation_instructions(user)
|
||||
do_flash(*get_message('CONFIRM_REGISTRATION', email=user.email))
|
||||
|
||||
data = dict(user=u, confirm_token=t)
|
||||
user_registered.send(data, app=app._get_current_object())
|
||||
user_registered.send(dict(user=user, confirm_token=token),
|
||||
app=app._get_current_object())
|
||||
|
||||
_logger.debug('User %s registered' % u)
|
||||
_logger.debug('User %s registered' % user)
|
||||
|
||||
# Login the user if allowed
|
||||
if not _security.confirmable or _security.login_without_confirmation:
|
||||
login_user(u)
|
||||
if not _security.confirmable or _security.login_without_confirmation:
|
||||
after_this_request(_commit)
|
||||
login_user(user)
|
||||
|
||||
if _security.confirmable:
|
||||
do_flash(*get_message('CONFIRM_REGISTRATION', email=u.email))
|
||||
post_register_url = get_url(_security.post_register_view)
|
||||
post_login_url = get_url(_security.post_login_view)
|
||||
|
||||
return redirect(get_url(_security.post_register_view) or
|
||||
get_url(_security.post_login_view))
|
||||
|
||||
return render_template('security/register.html',
|
||||
register_user_form=form,
|
||||
**_security._run_ctx_processor('register'))
|
||||
return redirect(post_register_url or post_login_url)
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
def send_login():
|
||||
"""View function that sends login instructions for passwordless login"""
|
||||
form = PasswordlessLoginForm()
|
||||
|
||||
form = PasswordlessLoginForm()
|
||||
user = _datastore.find_user(**form.to_dict())
|
||||
|
||||
if user.is_active():
|
||||
send_login_instructions(user, form.next.data)
|
||||
do_flash(*get_message('LOGIN_EMAIL_SENT', email=user.email))
|
||||
msg = get_message('LOGIN_EMAIL_SENT', email=user.email)
|
||||
else:
|
||||
do_flash(*get_message('DISABLED_ACCOUNT'))
|
||||
msg = get_message('DISABLED_ACCOUNT')
|
||||
|
||||
return render_template('security/send_login.html', login_form=form,
|
||||
**_security._run_ctx_processor('send_login'))
|
||||
do_flash(*msg)
|
||||
return render_template('security/send_login.html',
|
||||
login_form=form,
|
||||
**_ctx('send_login'))
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
@@ -186,18 +192,14 @@ def token_login(token):
|
||||
|
||||
try:
|
||||
user, next = login_by_token(token)
|
||||
|
||||
except PasswordlessLoginError, e:
|
||||
if e.user:
|
||||
send_login_instructions(e.user, e.next)
|
||||
|
||||
do_flash(str(e), 'error')
|
||||
|
||||
return redirect(request.referrer or url_for_security('login'))
|
||||
return redirect(request.referrer or url_for('login'))
|
||||
|
||||
do_flash(*get_message('PASSWORDLESS_LOGIN_SUCCESSFUL'))
|
||||
|
||||
return redirect(next or get_url(_security.post_login_view))
|
||||
return redirect(next)
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
@@ -208,45 +210,35 @@ def send_confirmation():
|
||||
|
||||
if form.validate_on_submit():
|
||||
user = _datastore.find_user(**form.to_dict())
|
||||
|
||||
reset_confirmation_token(user)
|
||||
|
||||
send_confirmation_instructions(user)
|
||||
_logger.debug('%s request confirmation instructions' % user)
|
||||
|
||||
do_flash(*get_message('CONFIRMATION_REQUEST', email=user.email))
|
||||
|
||||
return render_template('security/send_confirmation.html',
|
||||
reset_confirmation_form=form,
|
||||
**_security._run_ctx_processor('send_confirmation'))
|
||||
**_ctx('send_confirmation'))
|
||||
|
||||
|
||||
def confirm_email(token):
|
||||
"""View function which handles a email confirmation request."""
|
||||
after_this_request(_commit_data)
|
||||
after_this_request(_commit)
|
||||
|
||||
try:
|
||||
user = confirm_by_token(token)
|
||||
_logger.debug('%s confirmed their email' % user)
|
||||
|
||||
except ConfirmationError, e:
|
||||
msg = (str(e), 'error')
|
||||
|
||||
_logger.debug('Confirmation error: ' + msg[0])
|
||||
|
||||
_logger.debug('Confirmation error: %s' % e)
|
||||
if e.user:
|
||||
reset_confirmation_token(e.user)
|
||||
|
||||
do_flash(*msg)
|
||||
|
||||
return redirect(get_url(_security.confirm_error_view) or
|
||||
url_for_security('send_confirmation'))
|
||||
send_confirmation_instructions(e.user)
|
||||
do_flash(str(e), 'error')
|
||||
confirm_error_url = get_url(_security.confirm_error_view)
|
||||
return redirect(confirm_error_url or url_for('send_confirmation'))
|
||||
|
||||
_logger.debug('%s confirmed their email' % user)
|
||||
do_flash(*get_message('EMAIL_CONFIRMED'))
|
||||
|
||||
login_user(user, True)
|
||||
|
||||
return redirect(get_url(_security.post_confirm_view) or
|
||||
get_url(_security.post_login_view))
|
||||
post_confirm_url = get_url(_security.post_confirm_view)
|
||||
post_login_url = get_url(_security.post_login_view)
|
||||
return redirect(post_confirm_url or post_login_url)
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
@@ -257,11 +249,8 @@ def forgot_password():
|
||||
|
||||
if form.validate_on_submit():
|
||||
user = _datastore.find_user(**form.to_dict())
|
||||
|
||||
reset_password_reset_token(user)
|
||||
|
||||
send_reset_password_instructions(user)
|
||||
_logger.debug('%s requested to reset their password' % user)
|
||||
|
||||
do_flash(*get_message('PASSWORD_RESET_REQUEST', email=user.email))
|
||||
|
||||
if _security.post_forgot_view:
|
||||
@@ -272,49 +261,42 @@ def forgot_password():
|
||||
|
||||
return render_template('security/forgot_password.html',
|
||||
forgot_password_form=form,
|
||||
**_security._run_ctx_processor('forgot_password'))
|
||||
**_ctx('forgot_password'))
|
||||
|
||||
|
||||
@anonymous_user_required
|
||||
def reset_password(token):
|
||||
"""View function that handles a reset password request."""
|
||||
|
||||
next, msg = None, None
|
||||
form = ResetPasswordForm(csrf_enabled=not app.testing)
|
||||
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
user = reset_by_token(token=token, **form.to_dict())
|
||||
|
||||
_logger.debug('%s reset their password' % user)
|
||||
|
||||
do_flash(*get_message('PASSWORD_RESET'))
|
||||
|
||||
login_user(user)
|
||||
|
||||
return redirect(get_url(_security.post_reset_view) or
|
||||
get_url(_security.post_login_view))
|
||||
|
||||
msg = get_message('PASSWORD_RESET')
|
||||
next = (get_url(_security.post_reset_view) or
|
||||
get_url(_security.post_login_view))
|
||||
except ResetPasswordError, e:
|
||||
msg = (str(e), 'error')
|
||||
|
||||
_logger.debug('Password reset error: ' + msg[0])
|
||||
|
||||
if e.user:
|
||||
reset_password_reset_token(e.user)
|
||||
|
||||
send_reset_password_instructions(e.user)
|
||||
msg = get_message('PASSWORD_RESET_EXPIRED',
|
||||
within=_security.reset_password_within,
|
||||
email=e.user.email)
|
||||
_logger.debug('Password reset error: ' + msg[0])
|
||||
|
||||
do_flash(*msg)
|
||||
do_flash(*msg)
|
||||
|
||||
if _security.reset_password_error_view:
|
||||
return redirect(get_url(_security.reset_password_error_view))
|
||||
if next:
|
||||
login_user(user)
|
||||
_logger.debug('%s reset their password' % user)
|
||||
return redirect(next)
|
||||
|
||||
return render_template('security/reset_password.html',
|
||||
reset_password_form=form,
|
||||
reset_password_token=token,
|
||||
**_security._run_ctx_processor('reset_password'))
|
||||
**_ctx('reset_password'))
|
||||
|
||||
|
||||
def create_blueprint(app, name, import_name, **kwargs):
|
||||
|
||||
Reference in New Issue
Block a user