Ensuring a single login per user

I just checked myself and yes, I did have to turn it into a string, since whatever object anvil uses is not serializable into a simple object for use in a simple object column. So you could use a text column instead.

  user_row = app_tables.users.get_by_id(anvil.users.get_user().get_id())
  user_row['context'] = str(anvil.server.context.client)

I have not built it out, but if I were to, I would have a function take the context object “string” and md5 hash it so I didn’t unnecessarily store user info I did not need and put it in a text column in the users table. This function would run in a server call alongside a successful anvil.users.login_with_form().

I would then create a server module security function that would compare the current context object hashed string, with whatever was in the table, and if it did not match, run anvil.users.logout().

I might even create an @decorator for this purpose.

from functools import wraps

def with_user_security(func):
  
  @wraps(func)
  def wrapper_func(*args, **kwargs):
    if not your_context_compare_function_here():
        anvil.users.logout()
        #return #  ?? how you want to handle security is up to you
    func(*args, **kwargs)
  return wrapper_func

then later:

@anvil.server.callable
@with_user_security
def any_callable_nmvega_function():
    ...

So yes,

It should handle itself, if you have most of the important bits of whatever you are doing protected inside the server modules. (Otherwise you really don’t need/have any security anyway)

3 Likes