gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
30.69k stars 2.28k forks source link

Can Gradio only allow the same account to log in on one client? #8413

Closed coolboyqu closed 4 weeks ago

coolboyqu commented 1 month ago

By using .launch(auth=fun), a limited number of users can log in to the system, but they can log in simultaneously on multiple clients, affecting each other. Can it be achieved in Gradio that an account can only log in on one client, and when this account logs in on another client, it can be forcibly logged out and returned to the login interface.

I don't know how to log out from the user interface to Auth's login interface now. It seems that logoutbtn cannot be used here?

abidlabs commented 4 weeks ago

Hi @coolboyqu you can achieve something like this using the load() and unload() events of Blocks(). This isn't meant to be a production-grade auth solution, but:

import gradio as gr

logged_in_users = set()

def add(request: gr.Request):
    username = request.username
    print("logged_in_users", logged_in_users)
    if username in logged_in_users:
        return gr.Markdown(f"Only 1 session at a time, {username}")
    logged_in_users.add(username)
    return gr.Markdown(f"Welcome, {username}")

def remove(request: gr.Request):
    logged_in_users.pop(request.username)

with gr.Blocks() as demo:
    m = gr.Markdown()
    demo.load(add, None, m)
    demo.unload(remove)

demo.launch(auth=[("a", "a"), ("b", "b")])
delonleo commented 2 weeks ago

Hi @abidlabs

Thank you for the explanation. Would u know if we can use block instead ?

import gradio as gr

logged_in_users = set()

def add(request: gr.Request):
    username = request.username
    print("logged_in_users", logged_in_users)
    if username in logged_in_users:
        with gr.Blocks() as block:
            gr.Markdown(f"Only 1 session at a time, {username}")
        return block
    logged_in_users.add(username)
    with gr.Blocks() as block:
        gr.Markdown(f"Welcome, {username}")
    return block

def remove(request: gr.Request):
    if request.username in logged_in_users:
        logged_in_users.remove(request.username)

with gr.Blocks() as demo:
    demo.load(add, None, gr.Blocks())
    demo.unload(remove)

demo.launch(auth=[("a", "a"), ("b", "b")])
  File "/usr/local/lib/python3.10/dist-packages/gradio/queueing.py", line 532, in process_events
    response = await route_utils.call_process_api(
  File "/usr/local/lib/python3.10/dist-packages/gradio/route_utils.py", line 276, in call_process_api
    output = await app.get_blocks().process_api(
  File "/usr/local/lib/python3.10/dist-packages/gradio/blocks.py", line 1938, in process_api
    data = await self.postprocess_data(block_fn, result["prediction"], state)
  File "/usr/local/lib/python3.10/dist-packages/gradio/blocks.py", line 1739, in postprocess_data
    prediction_value = prediction_value.constructor_args.copy()
  File "/usr/local/lib/python3.10/dist-packages/gradio/blocks.py", line 157, in constructor_args
    return self._constructor_args[0] if self._constructor_args else {}
AttributeError: 'Blocks' object has no attribute '_constructor_args'. Did you mean: 'constructor_args'?

Gradio V4.36.1

freddyaboulton commented 2 weeks ago

Hi @delonleo - you can't return a gr.Blocks from an event. It has to be a single (or list of) components.