我想在我闪亮的应用程序中添加验证码。我使用了
ShinyFriendlyCaptcha
包。这是我的MWE。它仅显示验证码。效果很好:
library(shiny)
library(ShinyFriendlyCaptcha)#devtools::install_github("mhanf/ShinyFriendlyCaptcha")
# UI
ui<-fluidPage(
sfc_output(
id = "test",
sitekey = 'FCMLPPDE8H8IO645',
lang = "en",
dark_mode = FALSE,
eu_endpoint = FALSE,
theme_bs5 = TRUE
)
)
# Server
server <- function(input, output) {
# shinyvalidate
# captcha response
captcha_result <- sfc_server(
id = "test",
secret = 'A1T24PTUO6EU091S3HVJC3FRN5UE3JPBQ6UDO3RI3R5NM3VE4J6AQ0A8HC',
sitekey = 'FCMLPPDE8H8IO645',
eu_endpoint = FALSE
)
}
# Run the application
shinyApp(ui = ui, server = server)
现在,我需要动态构建 UI:
library(shiny)
library(ShinyFriendlyCaptcha)#devtools::install_github("mhanf/ShinyFriendlyCaptcha")
ui<-uiOutput("body")
# Server
server <- function(input, output) {
# captcha response
captcha_result <- sfc_server(
id = "test",
secret = 'A1T24PTUO6EU091S3HVJC3FRN5UE3JPBQ6UDO3RI3R5NM3VE4J6AQ0A8HC',
sitekey = 'FCMLPPDE8H8IO645',
eu_endpoint = FALSE
)
output$body <- renderUI({
fluidPage(
sfc_output(
id = "test",
sitekey = 'FCMLPPDE8H8IO645',
lang = "en",
dark_mode = FALSE,
eu_endpoint = FALSE,
theme_bs5 = TRUE
)
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
此代码不显示任何内容(应用程序不会失败),并且此消息出现在控制台中:
Listening on http://127.0.0.1:5396
Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
我在这里发现了类似的问题,但没有帮助。知道如何解决吗?
问题是
ShinyFriendlyCaptcha::sfc_output
加载了一些 JavaScript,当 document.readyState
不再等于 loading
时,这些 JavaScript 会被触发。使用动态 UI,可以在您尝试添加验证码之前实现此状态(基本上在静态 UI 加载后)。
因此,所有设置代码都不会运行,因为 JS 会寻找它无法找到的适当的 div。如果打开开发者控制台,您会发现 JavaScript 执行得太早了:
按照目前
sfc_output
的实现方式,我猜你没有运气动态地使用它。一种粗略的解决方法是拆分 HTML 和 JS 依赖项,并使用
insertUI
将它们一个接一个地插入:
sfc_output2 <- function (id, sitekey = Sys.getenv("captcha_sitekey"), lang = "en",
eu_endpoint = FALSE, theme_bs5 = FALSE, dark_mode = FALSE) {
bs5_dep <- NULL
if (isTRUE(theme_bs5)) {
bs5_dep <- htmlDependency(name = "bs5_dep", version = "0.0.1",
package = "ShinyFriendlyCaptcha", src = "assets",
stylesheet = c(file = "bs5_style.css"))
bs5_dep <- tags$style(id = "frc-style", bs5_dep)
}
ns <- NS(id)
language <- c("en", "fr", "de", "it", "nl", "pt", "es", "ca",
"da", "ja", "ru", "sv", "el", "uk", "bg", "cs", "sk",
"no", "fi", "lt", "lt", "pl", "et", "hr", "sr", "sl",
"hu", "ro", "zh", "zh_TW", "vi")
match.arg(arg = lang, choices = language, several.ok = FALSE)
captcha_js1 <- htmltools::htmlDependency(name = "friendlyCaptcha1",
version = "0.9.10", package = "ShinyFriendlyCaptcha",
src = "assets", script = "widget.module.min.js", )
captcha_js2 <- htmltools::htmlDependency(name = "friendlyCaptcha2",
version = "0.9.10", package = "ShinyFriendlyCaptcha",
src = "assets", script = "widget.min.js")
captcha_js3 <- tags$script(paste0("shinyCaptcha = function(response) {\n Shiny.onInputChange('",
ns("captcha_response"), "', response);\n }"))
captcha_class <- "frc-captcha"
if (isTRUE(dark_mode)) {
captcha_class <- sprintf("%s dark", captcha_class)
}
endpoint <- "https://api.friendlycaptcha.com/api/v1/puzzle"
if (isTRUE(eu_endpoint)) {
endpoint <- "https://eu-api.friendlycaptcha.eu/api/v1/puzzle"
}
captcha <- div(class = captcha_class, `data-lang` = lang,
`data-sitekey` = sitekey, `data-callback` = I("shinyCaptcha"),
`data-puzzle-endpoint` = endpoint)
deps <- tagList(bs5_dep, captcha_js1, captcha_js2, captcha_js3)
input_captcha <- checkboxInput(inputId = ns("captchaId"),
label = NULL, value = FALSE)
input_captcha <- tagAppendAttributes(input_captcha, .cssSelector = "div",
style = "display:none;")
captcha <- tagInsertChildren(input_captcha, after = 1, captcha)
list(cap = captcha, deps = deps)
}
然后你可以像这样使用sfc_output2
:
library(ShinyFriendlyCaptcha)
library(htmltools)
ui<- fluidPage(
div(id = "mother")
)
# Server
server <- function(input, output, session) {
# captcha response
captcha_result <- sfc_server(
id = "test",
secret = 'A1T24PTUO6EU091S3HVJC3FRN5UE3JPBQ6UDO3RI3R5NM3VE4J6AQ0A8HC',
sitekey = 'FCMLPPDE8H8IO645',
eu_endpoint = FALSE
)
cap <- sfc_output2(
id = "test",
sitekey = 'FCMLPPDE8H8IO645',
lang = "en",
dark_mode = FALSE,
eu_endpoint = FALSE,
theme_bs5 = TRUE
)
insertUI("#mother", "afterBegin", cap$cap)
insertUI("#mother", "afterBegin", cap$deps)
}
# Run the application
shinyApp(ui = ui, server = server)