Shiny R中Logout按钮失效问题的排查与修复请求
Let's break down why your Logout button is failing and walk through the fixes to get it working properly.
Root Causes of the Issue
- Conflicting UI Rendering Logic: Your
observeEvent(input$logout)is manually rendering the login UI and settingUSER$Logged <- FALSE. But you already have anobserveblock that automatically switches UI based onUSER$Loggedstate. When you setUSER$Logged <- FALSE, that existingobservetriggers immediately, overriding the manual UI render and causing unexpected behavior (making the button seem unresponsive). - Unclosed UI Syntax: Your
ui1function has an unclosedtagList(missing a closing)), which can cause silent rendering errors. - SQL Injection Risk: Using
sprintfto build your login query is unsafe—malicious input could break or exploit your database. - Redundant Code: The
print(ui)line in your server is invalid (sinceuiisn't defined) and serves no purpose.
Fixed Full Code
UI Section
ui2 <- function(){ tagList( tabPanel(""), pageWithSidebar( headerPanel(""), sidebarPanel(actionButton("logout", "Logout")), mainPanel(tableOutput('aaa')) ) ) } ui1 <- function(){ tagList( h2("Hello", align = "center"), div( id = "login", wellPanel( textInput("userName", "Username"), passwordInput("passwd", "Password"), br(), actionButton("Login", "Log in") ) ) # Added missing closing div/tagList bracket ) }
Server Section
server <- function(input, output, session) { USER <- reactiveValues(Logged = FALSE) # Handle Login Logic observe({ if (!USER$Logged) { if (!is.null(input$Login) && input$Login > 0) { Username <- isolate(input$userName) Password <- isolate(input$passwd) # Use parameterized query to avoid SQL injection db <- RSQLite::dbConnect(RSQLite::SQLite(), dbname = "db.sqlite") query <- "SELECT rowid FROM users WHERE username = ? AND password = ?" user <- RSQLite::dbGetQuery(db, query, params = list(Username, Password)) RSQLite::dbDisconnect(db) if (length(user$rowid) == 1) { USER$Logged <- TRUE } } } }) # Handle UI Switching Based on Login State observe({ if (!USER$Logged) { output$page <- renderUI({ div(class = "outer", bootstrapPage("", ui1())) }) } else { output$page <- renderUI({ div( class = "outer", navbarPage( inverse = TRUE, title = paste("Welcome", isolate(input$userName), "!"), ui2() ) ) }) } }) # Simplified Logout Logic observeEvent(input$logout, { # Only update the reactive state—let the existing observe handle UI switching USER$Logged <- FALSE }) }
Database Setup Code
library(shiny) library(RSQLite) setwd("E:/shiny/Correct") # Adjust path as needed db <- dbConnect(SQLite(), dbname = "db.sqlite") dbSendQuery(conn = db, "CREATE TABLE IF NOT EXISTS users (username TEXT, password TEXT, email TEXT)") dbSendQuery(db, "INSERT OR IGNORE INTO users (username, password, email) VALUES ('ester', 'silva', 'abc@gmail.com');") dbDisconnect(db) # Added disconnect to clean up connection
Key Fixes Explained
- Simplified Logout Handler: We removed the manual UI render from
observeEvent(input$logout)—now it only updatesUSER$Logged <- FALSE. The existingobserveblock will automatically detect this state change and switch back to the login UI, eliminating conflicts. - Fixed UI Syntax: Closed the missing brackets in
ui1to ensure proper rendering. - Secure SQL Query: Replaced
sprintfwith a parameterized query usingparamsindbGetQuery—this prevents SQL injection and makes the query more robust. - Cleaned Up Database Code: Added
CREATE TABLE IF NOT EXISTSandINSERT OR IGNOREto avoid errors if the database already exists, plus addeddbDisconnectto properly close the database connection.
Now your Logout button will work as expected: clicking it will set USER$Logged to FALSE, triggering the UI switch back to the login screen, and allowing you to log in again with no issues.
内容的提问来源于stack exchange,提问作者Ester Silva
相关产品推荐
相关产品推荐

