Skip to content

Commit 4ba4ac2

Browse files
committed
adding flask security example code
1 parent 6fa03de commit 4ba4ac2

23 files changed

+1801
-36
lines changed
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
title: flask.ctx after_this_request code examples
2+
category: page
3+
slug: flask-ctx-after-this-request-examples
4+
sortorder: 500021007
5+
toc: False
6+
sidebartitle: flask.ctx after_this_request
7+
meta: Python example code for the after_this_request function from the flask.ctx module of the Flask project.
8+
9+
10+
after_this_request is a function within the flask.ctx module of the Flask project.
11+
12+
13+
## Example 1 from Flask-Security-Too
14+
[Flask-Security-Too](https://github.com/Flask-Middleware/flask-security/)
15+
([PyPi page](https://pypi.org/project/Flask-Security-Too/) and
16+
[project documentation](https://flask-security-too.readthedocs.io/en/stable/))
17+
is a maintained fork of the original
18+
[Flask-Security](https://github.com/mattupstate/flask-security) project that
19+
makes it easier to add common security features to [Flask](/flask.html)
20+
web applications. A few of the critical goals of the Flask-Security-Too
21+
project are ensuring JavaScript client-based single-page applications (SPAs)
22+
can work securely with Flask-based backends and that guidance by the
23+
[OWASP](https://owasp.org/) organization is followed by default.
24+
25+
The Flask-Security-Too project is provided as open source under the
26+
[MIT license](https://github.com/Flask-Middleware/flask-security/blob/master/LICENSE).
27+
28+
[**Flask-Security-Too / flask_security / unified_signin.py**](https://github.com/Flask-Middleware/flask-security/blob/master/flask_security/./unified_signin.py)
29+
30+
```python
31+
# unified_signin.py
32+
33+
import time
34+
35+
from flask import current_app as app
36+
~~from flask import abort, after_this_request, request, session
37+
from flask_login import current_user
38+
from werkzeug.datastructures import MultiDict
39+
from werkzeug.local import LocalProxy
40+
from wtforms import BooleanField, RadioField, StringField, SubmitField, validators
41+
42+
from .confirmable import requires_confirmation
43+
from .decorators import anonymous_user_required, auth_required, unauth_csrf
44+
from .forms import Form, Required, get_form_field_label
45+
from .quart_compat import get_quart_status
46+
from .signals import us_profile_changed, us_security_token_sent
47+
from .twofactor import is_tf_setup, tf_login
48+
from .utils import (
49+
_,
50+
SmsSenderFactory,
51+
base_render_json,
52+
check_and_get_token_status,
53+
config_value,
54+
do_flash,
55+
find_user,
56+
get_identity_attributes,
57+
get_post_login_redirect,
58+
get_post_verify_redirect,
59+
get_message,
60+
get_url,
61+
62+
63+
## ... source file abbreviated to get to after_this_request examples ...
64+
65+
66+
67+
def __init__(self, *args, **kwargs):
68+
super().__init__(*args, **kwargs)
69+
70+
def validate(self):
71+
if not super().validate():
72+
return False
73+
74+
if not _security._totp_factory.verify_totp(
75+
token=self.passcode.data,
76+
totp_secret=self.totp_secret,
77+
user=self.user,
78+
window=config_value("US_TOKEN_VALIDITY"),
79+
):
80+
self.passcode.errors.append(get_message("INVALID_PASSWORD_CODE")[0])
81+
return False
82+
83+
return True
84+
85+
86+
def _send_code_helper(form):
87+
user = form.user
88+
method = form.chosen_method.data
89+
totp_secrets = _datastore.us_get_totp_secrets(user)
90+
if method == "email" and method not in totp_secrets:
91+
~~ after_this_request(_commit)
92+
totp_secrets[method] = _security._totp_factory.generate_totp_secret()
93+
_datastore.us_put_totp_secrets(user, totp_secrets)
94+
95+
msg = user.us_send_security_token(
96+
method,
97+
totp_secret=totp_secrets[method],
98+
phone_number=getattr(user, "us_phone_number", None),
99+
send_magic_link=True,
100+
)
101+
code_sent = True
102+
if msg:
103+
code_sent = False
104+
form.chosen_method.errors.append(msg)
105+
return code_sent, msg
106+
107+
108+
@anonymous_user_required
109+
@unauth_csrf(fall_through=True)
110+
def us_signin_send_code():
111+
form_class = _security.us_signin_form
112+
113+
if request.is_json:
114+
if request.content_length:
115+
form = form_class(MultiDict(request.get_json()), meta=suppress_form_csrf())
116+
117+
118+
## ... source file abbreviated to get to after_this_request examples ...
119+
120+
121+
else:
122+
return redirect(get_post_login_redirect())
123+
124+
form_class = _security.us_signin_form
125+
126+
if request.is_json:
127+
if request.content_length:
128+
form = form_class(MultiDict(request.get_json()), meta=suppress_form_csrf())
129+
else:
130+
form = form_class(formdata=None, meta=suppress_form_csrf())
131+
else:
132+
form = form_class(meta=suppress_form_csrf())
133+
form.submit.data = True
134+
135+
if form.validate_on_submit():
136+
remember_me = form.remember.data if "remember" in form else None
137+
if (
138+
config_value("TWO_FACTOR")
139+
and form.authn_via in config_value("US_MFA_REQUIRED")
140+
and (config_value("TWO_FACTOR_REQUIRED") or is_tf_setup(form.user))
141+
):
142+
return tf_login(
143+
form.user, remember=remember_me, primary_authn_via=form.authn_via
144+
)
145+
146+
~~ after_this_request(_commit)
147+
login_user(form.user, remember=remember_me, authn_via=[form.authn_via])
148+
149+
if _security._want_json(request):
150+
return base_render_json(form, include_auth_token=True)
151+
152+
return redirect(get_post_login_redirect())
153+
154+
code_methods = _compute_code_methods()
155+
if _security._want_json(request):
156+
payload = {
157+
"available_methods": config_value("US_ENABLED_METHODS"),
158+
"code_methods": code_methods,
159+
"identity_attributes": get_identity_attributes(),
160+
}
161+
return base_render_json(form, include_user=False, additional=payload)
162+
163+
if current_user.is_authenticated:
164+
return redirect(get_post_login_redirect())
165+
166+
form.passcode.data = None
167+
return _security.render_template(
168+
config_value("US_SIGNIN_TEMPLATE"),
169+
us_signin_form=form,
170+
available_methods=config_value("US_ENABLED_METHODS"),
171+
172+
173+
## ... source file abbreviated to get to after_this_request examples ...
174+
175+
176+
if _security.redirect_behavior == "spa":
177+
return redirect(
178+
get_url(
179+
_security.login_error_view,
180+
qparams=user.get_redirect_qparams({c: m}),
181+
)
182+
)
183+
do_flash(m, c)
184+
return redirect(url_for_security("us_signin"))
185+
186+
if (
187+
config_value("TWO_FACTOR")
188+
and "email" in config_value("US_MFA_REQUIRED")
189+
and (config_value("TWO_FACTOR_REQUIRED") or is_tf_setup(user))
190+
):
191+
if _security.redirect_behavior == "spa":
192+
return redirect(
193+
get_url(
194+
_security.login_error_view,
195+
qparams=user.get_redirect_qparams({"tf_required": 1}),
196+
)
197+
)
198+
return tf_login(user, primary_authn_via="email")
199+
200+
login_user(user, authn_via=["email"])
201+
~~ after_this_request(_commit)
202+
if _security.redirect_behavior == "spa":
203+
return redirect(
204+
get_url(_security.post_login_view, qparams=user.get_redirect_qparams())
205+
)
206+
207+
do_flash(*get_message("PASSWORDLESS_LOGIN_SUCCESSFUL"))
208+
return redirect(get_post_login_redirect())
209+
210+
211+
@auth_required(
212+
within=lambda: config_value("FRESHNESS"),
213+
grace=lambda: config_value("FRESHNESS_GRACE_PERIOD"),
214+
)
215+
def us_setup():
216+
form_class = _security.us_setup_form
217+
218+
if request.is_json:
219+
if request.content_length:
220+
form = form_class(MultiDict(request.get_json()), meta=suppress_form_csrf())
221+
else:
222+
form = form_class(formdata=None, meta=suppress_form_csrf())
223+
else:
224+
form = form_class(meta=suppress_form_csrf())
225+
226+
227+
228+
## ... source file abbreviated to get to after_this_request examples ...
229+
230+
231+
form_class = _security.us_setup_validate_form
232+
233+
if request.is_json:
234+
form = form_class(MultiDict(request.get_json()), meta=suppress_form_csrf())
235+
else:
236+
form = form_class(meta=suppress_form_csrf())
237+
238+
expired, invalid, state = check_and_get_token_status(
239+
token, "us_setup", get_within_delta("US_SETUP_WITHIN")
240+
)
241+
if invalid:
242+
m, c = get_message("API_ERROR")
243+
if expired:
244+
m, c = get_message("US_SETUP_EXPIRED", within=config_value("US_SETUP_WITHIN"))
245+
if invalid or expired:
246+
if _security._want_json(request):
247+
payload = json_error_response(errors=m)
248+
return _security._render_json(payload, 400, None, None)
249+
do_flash(m, c)
250+
return redirect(url_for_security("us_setup"))
251+
252+
form.totp_secret = state["totp_secret"]
253+
form.user = current_user
254+
255+
if form.validate_on_submit():
256+
~~ after_this_request(_commit)
257+
method = state["chosen_method"]
258+
phone = state["phone_number"] if method == "sms" else None
259+
_datastore.us_set(current_user, method, state["totp_secret"], phone)
260+
261+
us_profile_changed.send(
262+
app._get_current_object(), user=current_user, method=method
263+
)
264+
if _security._want_json(request):
265+
return base_render_json(
266+
form,
267+
include_user=False,
268+
additional=dict(
269+
chosen_method=method, phone=current_user.us_phone_number
270+
),
271+
)
272+
else:
273+
do_flash(*get_message("US_SETUP_SUCCESSFUL"))
274+
return redirect(
275+
get_url(_security.us_post_setup_view)
276+
or get_url(_security.post_login_view)
277+
)
278+
279+
if _security._want_json(request):
280+
return base_render_json(form, include_user=False)
281+
282+
283+
## ... source file continues with no further after_this_request examples...
284+
285+
```
286+

content/pages/examples/flask/flask-ctx-has-app-context.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
title: flask.ctx has_app_context code examples
22
category: page
33
slug: flask-ctx-has-app-context-examples
4-
sortorder: 500021007
4+
sortorder: 500021008
55
toc: False
66
sidebartitle: flask.ctx has_app_context
77
meta: Python example code for the has_app_context function from the flask.ctx module of the Flask project.

content/pages/examples/flask/flask-ctx-has-request-context.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
title: flask.ctx has_request_context code examples
22
category: page
33
slug: flask-ctx-has-request-context-examples
4-
sortorder: 500021008
4+
sortorder: 500021009
55
toc: False
66
sidebartitle: flask.ctx has_request_context
77
meta: Python example code for the has_request_context function from the flask.ctx module of the Flask project.

content/pages/examples/flask/flask-extensions-plug-ins.markdown

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ Flask RESTX is provided as open source under the
102102
[BSD 3-Clause license](https://github.com/python-restx/flask-restx/blob/master/LICENSE).
103103

104104

105+
### Flask-Security-Too
106+
[Flask-Security-Too](https://github.com/Flask-Middleware/flask-security/)
107+
([PyPi page](https://pypi.org/project/Flask-Security-Too/) and
108+
[project documentation](https://flask-security-too.readthedocs.io/en/stable/))
109+
is a maintained fork of the original
110+
[Flask-Security](https://github.com/mattupstate/flask-security) project that
111+
makes it easier to add common security features to [Flask](/flask.html)
112+
web applications. A few of the critical goals of the Flask-Security-Too
113+
project are ensuring JavaScript client-based single-page applications (SPAs)
114+
can work securely with Flask-based backends and that guidance by the
115+
[OWASP](https://owasp.org/) organization is followed by default.
116+
117+
The Flask-Security-Too project is provided as open source under the
118+
[MIT license](https://github.com/Flask-Middleware/flask-security/blob/master/LICENSE).
119+
120+
105121
### Flask-WTF
106122
[Flask-WTF](https://github.com/lepture/flask-wtf)
107123
([project documentation](https://flask-wtf.readthedocs.io/en/stable/)

0 commit comments

Comments
 (0)