I wanted to have signed URL everywhere.For that, I added user_signature=True to all my URL(). The grid has that as a default.At this point everything worked with @requires_login() except one special case (I believe this special case may be related to the same issue I'm facing with this I describe here).Then I added a var called sid (for session id) to every URL() which I use to identify the session (this way I'm able to distinguish ebetween 2 browser tabs).At this point everything worked with @requires_login() except the special case I mentioned above.Then I replaced @auth.requires_login() with @auth.requires_signature() and I'm able to access the grid but not the edit form. I receive a Not Authorized message.In all these tests I'm logged in.If I remove the sid var and keep the @auth.requires_signature() everything works.If I replace t...@auth.requires_signature() with @auth.requires_login() and keep the sid var everything works.Only the combination of both doesn't work.
#@auth.requires_signature()
@auth.requires_login()
def index():
# type: () -> Dict[str, gluon.DIV]
"""Index page.
:return: Dict with grid.
"""
if session.return_to:
del session.return_to
session.table = 'opt_cat'
# Hidden fields in grid and edit/view form.
db.opt_cat.id.readable = False
db.opt_cat.one_opt_only.show_if = db.opt_cat.mandatory == False
if SUPERVISOR_ROLE_ID in auth.user_groups:
# Uses covering index opt_cat_is_active_name_en.
# Uses auto index sqlite_autoindex_opt_cat_1.
grid = SQLFORM.grid(
db.opt_cat,
csv=False,
details=False,
# Disable delete checkbox in edit form.
editargs=dict(deletable=False),
maxtextlength=GRID_COL_LEN_FOR_TEXT,
ondelete=on_delete, # Grid only.
onvalidation=on_validation, # And onupdate are form only.
orderby=db.opt_cat.name,
paginate=session.auth.user.pagination,
# represent_none='', # Grid and view form only.
) # type: gluon.DIV
else:
# Hidden fields in grid and edit/view form.
db.opt_cat.canceled_on.readable = False
db.opt_cat.canceled_by.readable = False
db.opt_cat.cancel_approved_by.readable = False
# Uses covering index opt_cat_is_active_name_en (is_active=?).
# Uses index opt_cat_is_active_name (is_active=?).
grid = SQLFORM.grid(
db.opt_cat.is_active == True,
create=False,
csv=False,
deletable=False,
details=False,
editable=False,
maxtextlength=GRID_COL_LEN_FOR_TEXT,
orderby=db.opt_cat.name,
paginate=session.auth.user.pagination,
# represent_none='', # Grid and view form only.
)
# Remove icons from default buttons.
grid.elements('span.icon', replace=None)
if request.args:
# Remove delete button.
grid.element('#delete_with_approval', replace=None)
if not request.args:
# Sort grid's search fields list.
grid.element('#w2p_query_fields').components = sort_grid_search_fields_list(grid)
if session.opt_cat_modified_on:
del session.opt_cat_modified_on
elif 'edit' in request.args:
# Edit uses opt_cat Pk.
form = grid.update_form # type: gluon.sqlhtml.SQLFORM
# form['hidden'].update(mon=form.record.modified_on)
# Solves the record changed while editing, but doesn't solve it
# if the user 1st tries something that returns form.errors (eg.
# changing a unique field to something that already exists) and
# only after that he tries to save the record (which was changed
# by another user). For this the only solution I've found was
# using a session var.
if not session.opt_cat_modified_on:
session.opt_cat_modified_on = form.record.modified_on
if not form.record.is_active and not SUPERVISOR_ROLE_ID in auth.user_groups:
session.flash = T('Record was deleted while you were viewing the grid.')
redirect(URL(user_signature=True))
return dict(grid=grid)
...
if auth.is_logged_in():
response.menu = [
(T('Home'), False, URL('default', 'index', user_signature=True)),
(T('Open work orders'), False, URL('open_wo', 'index', user_signature=True)),
(T('Tables'),
False,
None,
[
(db.opt_cat._plural, False, URL('opt_cat', 'index', vars={'sid': request.vars.sid}, user_signature=True)),
...
It is called from the menu (models\menu.py). This is the code:
...
if auth.is_logged_in():
response.menu = [
(T('Home'), False, URL('default', 'index', user_signature=True)),
(T('Open work orders'), False, URL('open_wo', 'index', user_signature=True)),
(T('Tables'),
False,
None,
[
(db.opt_cat._plural, False, URL('opt_cat', 'index', vars={'sid': request.vars.sid}, user_signature=True)),
...Didn't test the sorting or search then, but I tested now and they also don't work, returning the same Not Authorized message.
@auth.requires_signature(hash_vars=False)
URL('opt_cat', 'index', vars={'sid': request.vars.sid}, user_signature=True, hash_vars=False)
My though in replacing the @auth.requires_login() with @auth.requires_signature() (I believe @auth.requires_signature() also requires login, correct?) was adding another security layer, but with the limitation you explained, I think I will not do it.What is your opinion on this?With this severe limitation to @auth.requires_signature(), in what situation do you recommend using it?