I am creating an application that has SSO authentication. Once the authentication is done, I can get the user details using request.session.get('user')
.
I created a variable user_details = {}
outside the server function of shiny and assigned the session details into it and it was working fine. The issue is, this data will be remained in the server when each user logs in. When me and my friend logged into the webpage after completing my SSO, he saw my name in his session.
After a bit research, I came to know that I need to put the user_details
variable inside the server function in shiny but after doing this, I am not able to assign the session user details to the variable.
Code:
def server(input, output, session):
user_details = session.user
print(user_details)
shiny_app = App(app_ui, server)
#----------------------------------------------------------------------END OF SHINY-----------------------------------------------------
#---------------------------------------------------------------------START OF SSO-------------------------------------------------------
config = Config('.env')
oauth = OAuth()
CONF_URL = #config url
oauth.register(
name = "app",
server_metadata_url = CONF_URL,
client_id = config.get('client_id'),
client_secret = config.get('client_secret'),
client_kwargs={
'scope': 'openid email'
}
)
random_secret_key = secrets.token_urlsafe(32)
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Check if the user is authenticated
user = request.session.get("user")
# List of paths that require authentication
protected_paths = ["/dash", "/dash/"]
# If the path is protected and the user is not authenticated
if request.url.path in protected_paths and not user:
#Redirect to the login page or SSO login flow
return RedirectResponse(url="/login")
# Proceed with the next middleware or route handler
response = await call_next(request)
return response
async def homepage(request):
global user_details
user = request.session.get('user')
if user:
return RedirectResponse(url='/dash')
#return JSONResponse(user)
return RedirectResponse(url = '/login')
async def login(request):
redirect_uri = request.url_for('auth')
return await oauth.app.authorize_redirect(request, redirect_uri)
async def auth(request):
token = await oauth.app.authorize_access_token(request)
user = token.get('userinfo')
if user:
request.session['user'] = user
return RedirectResponse(url='/')
async def healthcheck(request):
return JSONResponse({"Status" : "running"}, headers = {"Cache-Control" : "max-age=0, no-cache, no-store"})
routes = [
Route('/health/ping', healthcheck),
Route('/', homepage),
Route('/login', login),
Route('/auth', auth),
Mount('/Static', StaticFiles(directory = 'www'), name = 'static'),
Mount('/dash', app = shiny_app)
]
app = Starlette(routes=routes)
app.add_middleware(AuthMiddleware)
app.add_middleware(SessionMiddleware, secret_key = random_secret_key)
I used the session.get_current_session()
method which is described in the documentation, but it says "AppSession" object don't have no attribute get_current_session()
method.
To anyone who is looking for an answer, put all your variables that needs to be independent or refreshed in each session in the server function of shiny. This make sure all the variables are now newly created for each users who is logging into the server.
next, you need to update the user info from cookies. so far this is the best solution I found out. You need to read the cookie when user hit the root of the webpage and also you need to read the data from cookie from all the possible url from the server. I added a separate middleware to handle the request when user hit from "/dash" url. so when user access my webpage from "/dash" url, my middleware will go and read the data from the cookie and will load it into the session. I think there will be better solution for this than adding middleware to all the possible url in the server. but for now, this method worked for me.