Open daattali opened 3 years ago
I agree with @daatalli, authentication in UI would be great.
Is there any workround for this problem @JohnCoene.
Yes indeed, it does get tedious.
It could be done but it's quite a bit of work.
There are two ways I can think of doing this: by hijacking the app
object as returned by shinyApp
to, instead of returning the UI as response, return the login screen (when GET /
).
Then either upon login load the shiny UI via websocket (can't return another response), or from the UI screen exectute a POST
to another handler (e.g.: /login
) which would return the UI.
The first is likely to cause issues with the rendering of some things as the UI is not meant to be loaded like that (e.g.: dependencies), the second is rather convoluted as it feels like we're logging people in twice.
There might be an easier way but I'm not seeing it.
Currently, using modules it's possible to reduce the use req_sign_in
somewhat.
observeEvent(f$req_sign_in(), {
callModule(module_name_server, "module_name")
})
Here's a potential workaround: build your ui()
as usual, but wrap it in a call to shiny::renderUI()
with a single f$req_sign_in()
.
The toy example below works for me: the text "Logged in!" doesn't show up in the html (as inspected using Chrome's dev panel) until you log in. I haven't tested it with a full app, but it worked okay with some buttons and other inputs and outputs.
Here's a screenshot showing the empty div "logged_in_ui" using this method:
Using firebase::reqSignIn()
seems to just hide elements, so they can be found in the html. Here's the same ui wrapped in reqSignIn()
: the text is there, just made invisible with the css style = display: none;
.
This is a very minimal example, so maybe there are disadvantages in more complex cases--@JohnCoene, are there any obvious reasons this is a bad idea?
ui_secure <- fluidPage(
useFirebase(), # import dependencies
firebaseUIContainer(),
shiny::uiOutput("logged_in_ui")
)
ui_secret <- shiny::fluidPage(
h4("Logged in!")
)
server <- function(input, output){
f <- FirebaseUI$
new()$ # instantiate
set_providers( # define providers
email = TRUE,
google = TRUE
)$
launch() # launch
output$logged_in_ui <- shiny::renderUI({
f$req_sign_in()
ui_secret
})
}
shiny::shinyApp(ui = ui_secure, server = server)
I'm posting here since there's been more discussion, but it's mostly a duplicate of this issue.
@chris31415926535 Thank you for the solution above. I am trying to extend it with using a modal dialog. It works nicely for sign in but when signed out, It does not show the firebaseUI again. I'll appreciate any advice.
library(shiny)
library(firebase)
library(bslib)
# Firebase project configuration ------------------------------------------
firebase::firebase_config(api_key = "API_KEY",
project_id = "PROJECT_ID",
app_id = "APP_ID",
overwrite = TRUE)
# define signin
signin <- modalDialog(
title = "Welcome. Please Sign in.",
# useFirebase(),
firebaseUIContainer(),
footer = NULL
)
ui_dashboard <- page_navbar(
title = "title",
sidebar = sidebar("Sidebar"),
nav_panel("P1", "Page 1 content"),
nav_panel("P2", "Page 2 content"),
nav_panel("P3", "Page 3 content"),
nav_panel("P4", "Page 4 content"),
## Space between sections and sign out button
nav_spacer(),
## Sign out button
nav_item(
uiOutput("sign_out_button")
)
)
ui <- page_fillable(
useFirebase(),
shiny::uiOutput("logged_in_ui", fill = TRUE)
)
server <- function(input, output) {
showModal(signin)
f <- FirebaseUI$new()$set_providers(
email = TRUE,
google = TRUE)$launch()
observe({
f$req_sign_in()
removeModal()
})
output$sign_out_button <- shiny::renderUI({
f$req_sign_in()
actionButton("signout", "Sign out")
})
observeEvent(input$signout, {
f$sign_out()
# Show the modal dialog
showModal(signin)
})
output$logged_in_ui <- shiny::renderUI({
f$req_sign_in()
ui_dashboard
})
}
shinyApp(ui, server)
I'm not sure how, or if it's possible, but the current way of requiring all content to use either
f$req_sign_in()
orreqSignin()
seems like it would get tedious and very verbose very fast. It would be good to have bypass that, like how RStudio's authentication and {auth0} really don't load the UI until it's safe to do so