简体   繁体   中英

Rshiny: How can I call my JS authentication function such that the Rshiny app can consume the result?

So I have an Rshiny application set to publish on server, but we need an API authentication token to ensure a given user has access. The Authentication process is handled in JS tags outside of the app, while the actual Rshiny process is held in an iFrame on the page.

I have the js script saved externally in a www/ subdirectory packaged with the app. The JS script queries a value in localStorage to determine the userID, and pings the API validation with this token to determine access. It looks like this (fetch is a custom function that queries local storage to set the auth value).

/**
 * This Fn ! using to vaidate the user login access
 * @param none
 */
(function validateUserLoginInfo() {
    console.log("Sending user acess");
    var url = `https://authentication-url.com/isAuthy `;
    fetch(url, { method: 'GET' }, function (response) {
        if (response) {
            // user validation is Successfully done
            // $("#userValidated").val("Yes");
        } else {
            //invalid user access/login failure
            //Shiny.setInputValue("userValidated","No")
            // $("#userValidated").val("No");
        }
    });
})(); // => self executing Fn !

What I'm essentially trying to do is run this JS function such that a success yields an input passed into the Rshiny server environment, eg input$isUserValidated, so I can route the app processes and alert the instance that the user does not have access. I have it setup such that the "Welcome" page text changes based on this validation response, and the actual tabs with analysis are subsequently hidden from the instance.

In the if (response) else calls in the JS function, the commented out lines are the attempts I've made to pass the response to the server environment, but these haven't worked. And I believe the way I'm calling this function from the application is working, but I'm not sure if the function validateUserLoginInfo is actually working.

So I can break down my confusion into two steps really

  1. After sourcing the script, either via tags$head(tags$script(type="text/javascript", src = "www/authenticateUser.js")) or includeScript('www/authenticateUser.js') how can I run the actual validateUserLoginInfo() function from the r server? Or is it already run automatically on app load?

  2. Upon calling validateUserLoginInfo() , how can I pass the response from that call such that the R server can consume it?

Here's a hopefully simple app that captures what I'm looking for. The "authenticateUser.js" function can be considered a function that returns a simple "Yes" or "No", and I'm merely trying to access that answer from the R server.

ui <- fluidPage(
  includeScript('www/authenticateUser.js')
  textOutput('authed'),
)
server <- function(input,output,session){
  output$authed <- renderText({
    # No clue which one of these works; none have worked for me so far
    response <- input$userValidated
    response2 <- validateUserLoginInfo()
    response3 <- shinyjs::js$validateUserLoginInfo()
    return(c(response,response2,response3))
  })
}

I've looked far and wide for answers and can't seem to find anything that gets at what I need to accomplish here. Sending alerts or onClick events from JS <-> Shiny seems to be what most people use JS for w.r.t. Rshiny. So any and all help is appreciated. Thank you.

In the Shiny server, try wrapping the output of renderText inside an observeEvent that runs when the value userValidated changes.

server <- function(input, output, session) {
  observeEvent(input$userValidated, {
    output$auth <- renderText({
       input$userValidated
    })
  }, ignoreNULL = TRUE)
}

In the js function validateuserLoginInfo , use response.ok to evaluate the status of the request and set the value of userValidated accordingly.

I am not sure what information you need to send with the request, so here is an example that demonstrates the concepts. In the example, I wrote a short request that evaluates if the RStudio and RStudi are valid GitHub users (the second url will fail when used in the request).

library(shiny)

# js
js <- '
// validate user (this will run on page load)
(function validateUserLoginInfo() {
    console.log("Sending user acess");

    // set url (using github API as a generic example; test each url)
    //var url = "https://api.github.com/users/rstudio" // this will pass
    var url = "https://api.github.com/users/rstudi" // this will fail

    // create a new request
    fetch(url, {method: "GET"})
    .then((response) => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error(response.status);
        }
    })
    .then((result) => {

        // set shiny input as true
        Shiny.setInputValue("userValidated", JSON.stringify(true));

    }).catch((error) => {

        // set input as false + log error
        Shiny.setInputValue("userValidated", JSON.stringify(false));
        console.log(error);
    });

})();
'

# ui
ui <- fluidPage(
  textOutput("authed"),
  tags$script(HTML(js))
)

# server
server <- function(input, output, session) {

    # run when change
    observeEvent(input$userValidated, {
        response <- jsonlite::fromJSON(input$userValidated)
        output$authed <- renderPrint({
            response
        })
    }, ignoreNULL = TRUE)
}

# app
shinyApp(ui, server)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM