|
| 1 | +title: flask.globals session Python code examples |
| 2 | +category: page |
| 3 | +slug: flask-globals-session-examples |
| 4 | +sortorder: 500021001 |
| 5 | +toc: False |
| 6 | +sidebartitle: flask.globals session |
| 7 | +meta: Python example code for the session function from the flask.globals module of the Flask project. |
| 8 | + |
| 9 | + |
| 10 | +session is a function within the flask.globals module of the Flask project. |
| 11 | + |
| 12 | + |
| 13 | +## Example 1 from Flask AppBuilder |
| 14 | +[Flask-AppBuilder](https://github.com/dpgaspar/Flask-AppBuilder) |
| 15 | +([documentation](https://flask-appbuilder.readthedocs.io/en/latest/) |
| 16 | +and |
| 17 | +[example apps](https://github.com/dpgaspar/Flask-AppBuilder/tree/master/examples)) |
| 18 | +is a web application generator that uses Flask to automatically create |
| 19 | +the code for database-driven applications based on parameters set |
| 20 | +by the user. The generated applications include default security settings, |
| 21 | +forms, and internationalization support. |
| 22 | + |
| 23 | +Flask App Builder is provided under the |
| 24 | +[BSD 3-Clause "New" or "Revised" license](https://github.com/dpgaspar/Flask-AppBuilder/blob/master/LICENSE). |
| 25 | + |
| 26 | +[**Flask AppBuilder / flask_appbuilder / security / registerviews.py**](https://github.com/dpgaspar/Flask-AppBuilder/blob/master/flask_appbuilder/security/registerviews.py) |
| 27 | + |
| 28 | +```python |
| 29 | +# registerviews.py |
| 30 | +__author__ = "Daniel Gaspar" |
| 31 | + |
| 32 | +import logging |
| 33 | + |
| 34 | +~~from flask import flash, redirect, request, session, url_for |
| 35 | +from flask_babel import lazy_gettext |
| 36 | +from flask_openid import OpenIDResponse, SessionWrapper |
| 37 | +from openid.consumer.consumer import CANCEL, Consumer, SUCCESS |
| 38 | + |
| 39 | +from .forms import LoginForm_oid, RegisterUserDBForm, RegisterUserOIDForm |
| 40 | +from .. import const as c |
| 41 | +from .._compat import as_unicode |
| 42 | +from ..validators import Unique |
| 43 | +from ..views import expose, PublicFormView |
| 44 | + |
| 45 | +log = logging.getLogger(__name__) |
| 46 | + |
| 47 | + |
| 48 | +def get_first_last_name(fullname): |
| 49 | + names = fullname.split() |
| 50 | + if len(names) > 1: |
| 51 | + return names[0], " ".join(names[1:]) |
| 52 | + elif names: |
| 53 | + return names[0], "" |
| 54 | + |
| 55 | + |
| 56 | +class BaseRegisterUser(PublicFormView): |
| 57 | + """ |
| 58 | + Make your own user registration view and inherit from this class if you |
| 59 | +
|
| 60 | +
|
| 61 | +## ... source file abbreviated to get to session examples ... |
| 62 | +
|
| 63 | +
|
| 64 | +class RegisterUserOIDView(BaseRegisterUser): |
| 65 | + """ |
| 66 | + View for Registering a new user, auth OID mode |
| 67 | + """ |
| 68 | +
|
| 69 | + route_base = "/register" |
| 70 | +
|
| 71 | + form = RegisterUserOIDForm |
| 72 | + default_view = "form_oid_post" |
| 73 | +
|
| 74 | + @expose("/formoidone", methods=["GET", "POST"]) |
| 75 | + def form_oid_post(self, flag=True): |
| 76 | + if flag: |
| 77 | + self.oid_login_handler(self.form_oid_post, self.appbuilder.sm.oid) |
| 78 | + form = LoginForm_oid() |
| 79 | + if form.validate_on_submit(): |
| 80 | + session["remember_me"] = form.remember_me.data |
| 81 | + return self.appbuilder.sm.oid.try_login( |
| 82 | + form.openid.data, ask_for=["email", "fullname"] |
| 83 | + ) |
| 84 | +~~ resp = session.pop("oid_resp", None) |
| 85 | + if resp: |
| 86 | + self._init_vars() |
| 87 | + form = self.form.refresh() |
| 88 | + self.form_get(form) |
| 89 | + form.username.data = resp.email |
| 90 | + first_name, last_name = get_first_last_name(resp.fullname) |
| 91 | + form.first_name.data = first_name |
| 92 | + form.last_name.data = last_name |
| 93 | + form.email.data = resp.email |
| 94 | + widgets = self._get_edit_widget(form=form) |
| 95 | + # self.update_redirect() |
| 96 | + return self.render_template( |
| 97 | + self.form_template, |
| 98 | + title=self.form_title, |
| 99 | + widgets=widgets, |
| 100 | + form_action="form", |
| 101 | + appbuilder=self.appbuilder, |
| 102 | + ) |
| 103 | + else: |
| 104 | + flash(as_unicode(self.error_message), "warning") |
| 105 | + return redirect(self.get_redirect()) |
| 106 | +
|
| 107 | + def oid_login_handler(self, f, oid): |
| 108 | + """ |
| 109 | + |
| 110 | + |
| 111 | +## ... source file continues with no further session examples... |
| 112 | + |
| 113 | + |
| 114 | +``` |
| 115 | + |
| 116 | + |
| 117 | +## Example 2 from FlaskBB |
| 118 | +[FlaskBB](https://github.com/flaskbb/flaskbb) |
| 119 | +([project website](https://flaskbb.org/)) is a [Flask](/flask.html)-based |
| 120 | +forum web application. The web app allows users to chat in an open |
| 121 | +message board or send private messages in plain text or |
| 122 | +[Markdown](/markdown.html). |
| 123 | + |
| 124 | +FlaskBB is provided as open source |
| 125 | +[under this license](https://github.com/flaskbb/flaskbb/blob/master/LICENSE). |
| 126 | + |
| 127 | +[**FlaskBB / flaskbb / utils / helpers.py**](https://github.com/flaskbb/flaskbb/blob/master/flaskbb/utils/helpers.py) |
| 128 | + |
| 129 | +```python |
| 130 | +# helpers.py |
| 131 | +""" |
| 132 | +import ast |
| 133 | +import itertools |
| 134 | +import logging |
| 135 | +import operator |
| 136 | +import os |
| 137 | +import re |
| 138 | +import time |
| 139 | +import warnings |
| 140 | +from datetime import datetime, timedelta |
| 141 | +from email import message_from_string |
| 142 | +from functools import wraps |
| 143 | +
|
| 144 | +import pkg_resources |
| 145 | +import requests |
| 146 | +import unidecode |
| 147 | +from babel.core import get_locale_identifier |
| 148 | +from babel.dates import format_date as babel_format_date |
| 149 | +from babel.dates import format_datetime as babel_format_datetime |
| 150 | +from babel.dates import format_timedelta as babel_format_timedelta |
| 151 | +~~from flask import flash, g, redirect, request, session, url_for |
| 152 | +from flask_allows import Permission |
| 153 | +from flask_babelplus import lazy_gettext as _ |
| 154 | +from flask_login import current_user |
| 155 | +from flask_themes2 import get_themes_list, render_theme_template |
| 156 | +from jinja2 import Markup |
| 157 | +from PIL import ImageFile |
| 158 | +from pytz import UTC |
| 159 | +from werkzeug.local import LocalProxy |
| 160 | +from werkzeug.utils import ImportStringError, import_string |
| 161 | +
|
| 162 | +from flaskbb._compat import (iteritems, range_method, string_types, text_type, |
| 163 | + to_bytes, to_unicode) |
| 164 | +from flaskbb.extensions import babel, redis_store |
| 165 | +from flaskbb.utils.settings import flaskbb_config |
| 166 | +
|
| 167 | +try: # compat |
| 168 | + FileNotFoundError |
| 169 | +except NameError: |
| 170 | + FileNotFoundError = IOError |
| 171 | +
|
| 172 | +logger = logging.getLogger(__name__) |
| 173 | +
|
| 174 | +_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+') |
| 175 | +
|
| 176 | +
|
| 177 | +
|
| 178 | +## ... source file abbreviated to get to session examples ... |
| 179 | +
|
| 180 | +
|
| 181 | + result.append(word) |
| 182 | + return text_type(delim.join(result)) |
| 183 | +
|
| 184 | +
|
| 185 | +def redirect_or_next(endpoint, **kwargs): |
| 186 | + """Redirects the user back to the page they were viewing or to a specified |
| 187 | + endpoint. Wraps Flasks :func:`Flask.redirect` function. |
| 188 | + |
| 189 | + :param endpoint: The fallback endpoint. |
| 190 | + """ |
| 191 | + return redirect(request.args.get("next") or endpoint, **kwargs) |
| 192 | +
|
| 193 | +
|
| 194 | +def render_template(template, **context): # pragma: no cover |
| 195 | + """A helper function that uses the `render_theme_template` function |
| 196 | + without needing to edit all the views |
| 197 | + """ |
| 198 | + if current_user.is_authenticated and current_user.theme: |
| 199 | + theme = current_user.theme |
| 200 | + else: |
| 201 | +~~ theme = session.get("theme", flaskbb_config["DEFAULT_THEME"]) |
| 202 | + return render_theme_template(theme, template, **context) |
| 203 | +
|
| 204 | +
|
| 205 | +# TODO(anr): clean this up |
| 206 | +def do_topic_action(topics, user, action, reverse): # noqa: C901 |
| 207 | + """Executes a specific action for topics. Returns a list with the modified |
| 208 | + topic objects. |
| 209 | + |
| 210 | + :param topics: A iterable with ``Topic`` objects. |
| 211 | + :param user: The user object which wants to perform the action. |
| 212 | + :param action: One of the following actions: locked, important and delete. |
| 213 | + :param reverse: If the action should be done in a reversed way. |
| 214 | + For example, to unlock a topic, ``reverse`` should be |
| 215 | + set to ``True``. |
| 216 | + """ |
| 217 | + if not topics: |
| 218 | + return False |
| 219 | +
|
| 220 | + from flaskbb.utils.requirements import ( |
| 221 | + IsAtleastModeratorInForum, |
| 222 | + CanDeleteTopic, |
| 223 | + Has, |
| 224 | + ) |
| 225 | +
|
| 226 | +
|
| 227 | +
|
| 228 | +## ... source file continues with no further session examples... |
| 229 | +
|
| 230 | +
|
| 231 | +``` |
| 232 | +
|
| 233 | +
|
| 234 | +## Example 3 from Flask-WTF |
| 235 | +[Flask-WTF](https://github.com/lepture/flask-wtf) |
| 236 | +([project documentation](https://flask-wtf.readthedocs.io/en/stable/) |
| 237 | +and |
| 238 | +[PyPI page](https://pypi.org/project/Flask-WTF/)) |
| 239 | +provides a bridge between [Flask](/flask.html) and the the |
| 240 | +[WTForms](https://wtforms.readthedocs.io/en/2.3.x/) form-handling library. |
| 241 | +It makes it easier to use WTForms by reducing boilerplate code and |
| 242 | +shorter examples for common form operations as well as common security |
| 243 | +practices such as [CSRF](/cross-site-request-forgery-csrf.html). |
| 244 | +
|
| 245 | +[**Flask-WTF / flask_wtf / csrf.py**](https://github.com/lepture/flask-wtf/blob/master/flask_wtf/./csrf.py) |
| 246 | +
|
| 247 | +```python |
| 248 | +# csrf.py |
| 249 | +import hashlib |
| 250 | +import logging |
| 251 | +import os |
| 252 | +import warnings |
| 253 | +from functools import wraps |
| 254 | +
|
| 255 | +~~from flask import Blueprint, current_app, g, request, session |
| 256 | +from itsdangerous import BadData, SignatureExpired, URLSafeTimedSerializer |
| 257 | +from werkzeug.exceptions import BadRequest |
| 258 | +from werkzeug.security import safe_str_cmp |
| 259 | +from wtforms import ValidationError |
| 260 | +from wtforms.csrf.core import CSRF |
| 261 | +
|
| 262 | +from ._compat import FlaskWTFDeprecationWarning, string_types, urlparse |
| 263 | +
|
| 264 | +__all__ = ('generate_csrf', 'validate_csrf', 'CSRFProtect') |
| 265 | +logger = logging.getLogger(__name__) |
| 266 | +
|
| 267 | +
|
| 268 | +def generate_csrf(secret_key=None, token_key=None): |
| 269 | + """Generate a CSRF token. The token is cached for a request, so multiple |
| 270 | + calls to this function will generate the same token. |
| 271 | + |
| 272 | + During testing, it might be useful to access the signed token in |
| 273 | + ``g.csrf_token`` and the raw token in ``session['csrf_token']``. |
| 274 | + |
| 275 | + :param secret_key: Used to securely sign the token. Default is |
| 276 | + ``WTF_CSRF_SECRET_KEY`` or ``SECRET_KEY``. |
| 277 | + :param token_key: Key where token is stored in session for comparison. |
| 278 | + Default is ``WTF_CSRF_FIELD_NAME`` or ``'csrf_token'``. |
| 279 | + """ |
| 280 | +
|
| 281 | + secret_key = _get_config( |
| 282 | + secret_key, 'WTF_CSRF_SECRET_KEY', current_app.secret_key, |
| 283 | + message='A secret key is required to use CSRF.' |
| 284 | + ) |
| 285 | + field_name = _get_config( |
| 286 | + token_key, 'WTF_CSRF_FIELD_NAME', 'csrf_token', |
| 287 | + message='A field name is required to use CSRF.' |
| 288 | + ) |
| 289 | +
|
| 290 | + if field_name not in g: |
| 291 | + s = URLSafeTimedSerializer(secret_key, salt='wtf-csrf-token') |
| 292 | +
|
| 293 | +~~ if field_name not in session: |
| 294 | + session[field_name] = hashlib.sha1(os.urandom(64)).hexdigest() |
| 295 | +
|
| 296 | + try: |
| 297 | + token = s.dumps(session[field_name]) |
| 298 | + except TypeError: |
| 299 | + session[field_name] = hashlib.sha1(os.urandom(64)).hexdigest() |
| 300 | + token = s.dumps(session[field_name]) |
| 301 | +
|
| 302 | + setattr(g, field_name, token) |
| 303 | +
|
| 304 | + return g.get(field_name) |
| 305 | +
|
| 306 | +
|
| 307 | +def validate_csrf(data, secret_key=None, time_limit=None, token_key=None): |
| 308 | + """Check if the given data is a valid CSRF token. This compares the given |
| 309 | + signed token to the one stored in the session. |
| 310 | + |
| 311 | + :param data: The signed CSRF token to be checked. |
| 312 | + :param secret_key: Used to securely sign the token. Default is |
| 313 | + ``WTF_CSRF_SECRET_KEY`` or ``SECRET_KEY``. |
| 314 | + :param time_limit: Number of seconds that the token is valid. Default is |
| 315 | + ``WTF_CSRF_TIME_LIMIT`` or 3600 seconds (60 minutes). |
| 316 | + :param token_key: Key where token is stored in session for comparison. |
| 317 | + Default is ``WTF_CSRF_FIELD_NAME`` or ``'csrf_token'``. |
| 318 | + |
| 319 | + |
| 320 | +## ... source file abbreviated to get to session examples ... |
| 321 | + |
| 322 | + |
| 323 | + .. versionchanged:: 0.14 |
| 324 | + Raises ``ValidationError`` with a specific error message rather than |
| 325 | + returning ``True`` or ``False``. |
| 326 | + """ |
| 327 | +
|
| 328 | + secret_key = _get_config( |
| 329 | + secret_key, 'WTF_CSRF_SECRET_KEY', current_app.secret_key, |
| 330 | + message='A secret key is required to use CSRF.' |
| 331 | + ) |
| 332 | + field_name = _get_config( |
| 333 | + token_key, 'WTF_CSRF_FIELD_NAME', 'csrf_token', |
| 334 | + message='A field name is required to use CSRF.' |
| 335 | + ) |
| 336 | + time_limit = _get_config( |
| 337 | + time_limit, 'WTF_CSRF_TIME_LIMIT', 3600, required=False |
| 338 | + ) |
| 339 | +
|
| 340 | + if not data: |
| 341 | + raise ValidationError('The CSRF token is missing.') |
| 342 | +
|
| 343 | +~~ if field_name not in session: |
| 344 | + raise ValidationError('The CSRF session token is missing.') |
| 345 | +
|
| 346 | + s = URLSafeTimedSerializer(secret_key, salt='wtf-csrf-token') |
| 347 | +
|
| 348 | + try: |
| 349 | + token = s.loads(data, max_age=time_limit) |
| 350 | + except SignatureExpired: |
| 351 | + raise ValidationError('The CSRF token has expired.') |
| 352 | + except BadData: |
| 353 | + raise ValidationError('The CSRF token is invalid.') |
| 354 | +
|
| 355 | + if not safe_str_cmp(session[field_name], token): |
| 356 | + raise ValidationError('The CSRF tokens do not match.') |
| 357 | +
|
| 358 | +
|
| 359 | +def _get_config( |
| 360 | + value, config_name, default=None, |
| 361 | + required=True, message='CSRF is not configured.' |
| 362 | +): |
| 363 | + """Find config value based on provided value, Flask config, and default |
| 364 | + value. |
| 365 | + |
| 366 | + :param value: already provided config value |
| 367 | + :param config_name: Flask ``config`` key |
| 368 | + |
| 369 | + |
| 370 | +## ... source file continues with no further session examples... |
| 371 | + |
| 372 | + |
| 373 | +``` |
| 374 | + |
0 commit comments