You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny R中Logout按钮失效问题的排查与修复请求

Fixing the Non-Working Logout Button in Your Shiny App

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

  1. Conflicting UI Rendering Logic: Your observeEvent(input$logout) is manually rendering the login UI and setting USER$Logged <- FALSE. But you already have an observe block that automatically switches UI based on USER$Logged state. When you set USER$Logged <- FALSE, that existing observe triggers immediately, overriding the manual UI render and causing unexpected behavior (making the button seem unresponsive).
  2. Unclosed UI Syntax: Your ui1 function has an unclosed tagList (missing a closing )), which can cause silent rendering errors.
  3. SQL Injection Risk: Using sprintf to build your login query is unsafe—malicious input could break or exploit your database.
  4. Redundant Code: The print(ui) line in your server is invalid (since ui isn'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

  1. Simplified Logout Handler: We removed the manual UI render from observeEvent(input$logout)—now it only updates USER$Logged <- FALSE. The existing observe block will automatically detect this state change and switch back to the login UI, eliminating conflicts.
  2. Fixed UI Syntax: Closed the missing brackets in ui1 to ensure proper rendering.
  3. Secure SQL Query: Replaced sprintf with a parameterized query using params in dbGetQuery—this prevents SQL injection and makes the query more robust.
  4. Cleaned Up Database Code: Added CREATE TABLE IF NOT EXISTS and INSERT OR IGNORE to avoid errors if the database already exists, plus added dbDisconnect to 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:52:18