I am developing a R Shiny App and want to add user name and logins. I checked the RStudio demo but that is only using the ShinyServer Pro and I am using the mongolite packag
ShinyProxy, an open-source Docker- and Spring Java-based Shiny server, was designed to address this issue. It allows you to hard-code users in the application configuration file, connect to an LDAP server, use SSO/Keycloak, or Social network sign-in.
I recently wrote an R package that provides login/logout modules you can integrate with any bootstrap UI framework.
Blogpost with example using shinydashboard
Package repo
the inst/
directory in the package repo contains the code for the example app.
Well, you can do it via from code by using renderUI
and changing the UI on the fly. Here is an example of how to do it:
library(shiny)
library(ggplot2)
u <- shinyUI(fluidPage(
titlePanel("Shiny Password"),
sidebarLayout(position = "left",
sidebarPanel( h3("sidebar panel"),
uiOutput("in.pss"),
uiOutput("in.clr"),
uiOutput("in.titl"),
uiOutput("in.cnt"),
uiOutput("in.seed")
),
mainPanel(h3("main panel"),
textOutput('echo'),
plotOutput('stdplot')
)
)
))
pok <- F
s <- shinyServer(function(input, output)
{
output$in.pss <- renderUI({ input$pss; if (pok) return(NULL) else return(textInput("pss","Password:","")) })
output$in.clr <- renderUI({ input$pss; if (pok) return(selectInput("clr","Color:",c("red","blue"))) else return(NULL) })
output$in.titl <- renderUI({ input$pss; if (pok) return(textInput("titl","Title:","Data")) else return(NULL) })
output$in.cnt <- renderUI({ input$pss; if (pok) return(sliderInput("cnt","Count:",100,1000,500,5)) else return(NULL) })
output$in.seed <- renderUI({ input$pss; if (pok) return(numericInput("seed","Seed:",1234,1,10000,1)) else return(NULL) })
histdata <- reactive(
{
input$pss;
validate(need(input$cnt,"Need count"),need(input$seed,"Need seed"))
set.seed(input$seed)
df <- data.frame(x=rnorm(input$cnt))
}
)
observe({
if (!pok) {
password <- input$pss
if (!is.null(password) && password == "pass") {
pok <<- TRUE
}
}
}
)
output$echo = renderText(
{
if (pok) {
s <- sprintf("the %s is %s and has %d rows and uses the %d seed",
input$ent,input$clr,nrow(histdata()),input$seed)
} else {
s <- ""
}
return(s)
}
)
output$stdplot = renderPlot(
{
input$pss
if (pok) {
return(qplot(data = histdata(),x,fill = I(input$clr),binwidth = 0.2,main=input$titl))
} else {
return(NULL)
}
}
)
}
)
shinyApp(ui=u,server=s)
this at login:
And this once you have entered the hardcoded password "pass".
Of course programming this way is a bit awkward, but you could use tabs and hide them perhaps using a similar logic.
Or if you are using shinyServer you could probably put a filter in front of the site. But this is how I would approach it in Shiny.
You can add an authenticating proxy ahead of your Shiny application like this: https://www.datascienceriot.com/add-authentication-to-shiny-server-with-nginx/kris/
This is a skeleton Nginx configuration that redirects from HTTPS port 443 to your Shiny Server running on port 8000.
server {
listen 443;
server_name shinyservername;
ssl on;
ssl_certificate ...
ssl_certificate_key ...
ssl_dhparam ...
location / {
proxy_pass http://yourdestinationIP:8000;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Front-End-Https on;
proxy_set_header Accept-Encoding "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/htpasswd;
}
}
Set your host's firewall to open port 443, and only allow localhost connections to the Shiny Server on port 8000:
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp -s localhost --dport 8000 -j ACCEPT
iptables -A INPUT -p tcp --dport 8000 -j DROP
Add static credentials for one or more users into /etc/nginx/htpasswd
:
htpasswd –c /etc/nginx/htpasswd myshinyuser
One downside (of many) is that this will authenticate & authorise, but it won't pass the authenticated user information to your application. For that you would need Shiny Server Pro's authentication integration which passes you the user in the session.
I use shinyAppLogin instead of shinApp:
# R code
shinyAppLogin <- function( ui, server, title="Restricted Area", accounts = list(admin="admin"), ...) {
ui_with_login <- bootstrapPage(theme = "login_style.css",
div(class="login-page",
div(class="form",
h1(title), br(),
tags$form(class="login-form",
textInput(inputId = "user", label = NULL, placeholder="Username"),
passwordInput(inputId = "pass", label = "", placeholder = "Password" ),
actionButton(inputId = "login", label = "Login")
) ) ) )
server_with_login <- function(input, output, session) {
observeEvent(input$login, ignoreNULL = T, {
if ( input$user %in% names(accounts) && input$pass == accounts[[input$user]] ) {
removeUI(selector = "body", multiple = T, immediate = T, session = session)
insertUI(selector = "html", where = "beforeEnd", ui = ui, immediate = T, session = session )
server(session$input, session$output, session = session)
}
} ) }
shinyApp(ui = ui_with_login, server = server_with_login, ...)
}
then my code becomes: shinyAppLogin(my_ui, my_server)
Login screen when styles
then I used css from enter link description here just save your css in www/login_style.css
The polished
R package adds authentication and user management to any Shiny app: https://github.com/Tychobra/polished
Here is a screenshot of the default sign in page that you get with polished:
You can easily replace the placeholder logos and colors with your own branding on the sign in and register pages.
Polished also comes with a dashboard to manage the users of your app:
More detail: https://polished.tech/