r - Shiny 的 Azure WebApp 作为 Azure SQL Server 的用户进行身份验证

标签 r sql-server azure shiny

我正在构建一个以 SQL DB 作为后端的 Web 应用程序。我将这两个部分部署在 Azure 上,作为 Azure Webapp 和 SQL Server。

SQL 服务器通过 Azure AD (AAD) 进行保护。因此只有组中的用户才能访问数据库。

因此,我尝试设置一个工作流程,其中 Web 应用程序登录用户并收集他的访问 token 。然后使用该 token 查询SQL服务器。

我已在 AAD 中注册了该应用程序,该应用程序被授权读取用户 ID 并冒充用户。

我有以下在本地运行的代码。但我无法让它在 Docker 镜像中本地部署。

# app file
library(shiny)
library(tidyverse)
library(shinyjs)
library(AzureAuth)

db <- "Azure"
config <- config::get(config = db)

redirect <- 'http://localhost:1410/app/'

ui_func <- function(req) {
  useShinyjs()
  opts <- parseQueryString(req$QUERY_STRING)
  if( is.null(opts$code) ) {
    auth_uri <- build_authorization_uri(
                  resource = config$resource, 
                  tenant = config$tenant, 
                  app = config$app, 
                  redirect_uri = redirect, 
                  # version = 2, 
                  prompt = 'login')
    redir_js <- sprintf('location.replace(\"%s\");', auth_uri)
    tags$script(HTML(redir_js))
  } else {
    fluidPage(
        verbatimTextOutput('token1'), 
        verbatimTextOutput('token2'),
        verbatimTextOutput('token_list'),
        verbatimTextOutput('path'),
        tableOutput('files'),
        tableOutput("db_tables")
        )
  }
}

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


  opts <- parseQueryString(isolate(session$clientData$url_search))
  if(is.null(opts$code))
    return()
  #get_azure_token(
  #            config$resource, 
  #            config$tenant, 
  #            config$app,
  #            #pssw,
  #            # version = 2,
  #            auth_type = 'authorization_code', 
  #            use_cache = FALSE, 
  #            auth_code = opts$code) -> 
  tok1 <- NULL
  get_azure_token(
                  config$resource2, 
                  config$tenant, 
                  config$app, 
                  password = config$secret, 
                  auth_type = 'authorization_code', 
                  use_cache = FALSE, 
                  # auth_type='on_behalf_of', 
                  # on_behalf_of = tok1,
                  auth_code = opts$code
                  ) -> 
  tok2
  output$token <- renderPrint(tok1)
  output$token2 <- renderPrint(tok2)
  renderText({
    rappdirs::user_data_dir() %>% 
      fs::dir_ls() }) -> 
  output$path
  renderText({
    list_azure_tokens() 
  }) ->
  output$token_list

  renderTable({
    rappdirs::user_data_dir() %>% 
      fs::path(., 'AzureR') %>%
      fs::dir_ls(., all = TRUE) %>% 
      tibble::as_tibble()
  }) ->
  output$files
  
  pool <- NULL
  if(!is.null(tok2)) {
    if(db == "Azure") {
      pool::dbPool(
            drv = odbc::odbc(), 
            Driver = config$driver, 
            Server = config$server, 
            Database = config$database, 
            Port = config$port,
            Encrypt = config$encrypt,
            TrustServerCertificate = config$trustservercertificate,
            ConnectionTimeout = config$connectiontimeout,
            Authentication = config$authentication
            ) -> 
      pool
    } 
    if(db == "PCI") {
      pool::dbPool(
            odbc::odbc(),
            drv = odbc::odbc(), 
            Driver = config$driver, 
            Server = config$server, 
            Database = config$database, 
            TrustedConnection = config$trustedconnection
            ) -> 
      pool
    }
  }
  onStop(function() {
           pool::poolClose(pool)})
  reactive({
    dat <- NULL
    if(!is.null(pool)) {
      pool %>% 
        DBI::dbListTables(.) %>% 
        dplyr::as_tibble() -> 
      dat}
    return(dat)
  }) -> 
  db_tables
  output$db_tables <- renderTable({
    db_tables()})
}
shinyApp(ui_func, server)

Dockerfile

# Dockerfile to test azure
ARG SHINY_PORT=1410
ARG SHINY_HOST="127.0.0.1"
ARG DOCKER_DEPLOY="local"
FROM rocker/shiny-verse:4.0.5
ARG SHINY_PORT
ARG SHINY_HOST
ARG DOCKER_DEPLOY 

RUN apt-get update -y \
  && apt-get install -y \
    curl \
    gnupg

# See about installing ODBC drivers here: https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017
# Note that the driver version installed needs to match the version used in the code
# In this case for Ubuntu 18.04: ODBC SQL driver 17
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -

RUN curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list

RUN apt-get update -y
RUN ACCEPT_EULA=Y apt-get install -y msodbcsql17
RUN ACCEPT_EULA=Y apt-get install -y mssql-tools
RUN apt-get install -y unixodbc-dev


RUN echo "\noptions(shiny.port=${SHINY_PORT}, shiny.host='${SHINY_HOST}')\n" >> /usr/local/lib/R/etc/Rprofile.site

## add any R 
RUN R -e 'install.packages(c("fs", "pkgload", "remotes", "tibble", "lubridate","shiny", "shinyjs", "shinythemes", "hms", "tidyverse", "magrittr", "AzureAuth"), dependencies = TRUE)'
RUN R -e 'install.packages(c("DT", "odbc", "rmarkdown","janitor", "reactable", "pool", "config","RODBC","DBI", "httpuv"), dependencies = TRUE )'

RUN mkdir /srv/shiny-server/app \
  && chown -R shiny:shiny /srv/shiny-server/app
COPY . /srv/shiny-server/app/

# setup shiny server. Create nessesarry dirs for server
COPY ./shiny-server.sh /usr/bin/shiny-server.sh
RUN chmod +x /usr/bin/shiny-server.sh
COPY ./shiny-server.conf /etc/shiny-server/shiny-server.conf

EXPOSE 1410 

# start server. Use sh from rocker project
CMD ["/usr/bin/shiny-server.sh"]
# config file for app
default:
  resource: 'https://graph.microsoft.com/'
  # resource: 'https://management.azure.com' 
  # resource: 
  #   - 'https://graph.microsoft.com/.default'
  #   - 'openid'
  #   - 'profile'
  #   - 'email'
  #   - 'offline_access'
  #   # - 'User.Read'
  resource2: 'https://database.windows.net/'
  tenant: 'xxxxxxx'
  app: 'xxxxxxx'
  secret: 'xxxxxxxxx'
  driver: 'ODBC Driver 17 for SQL Server'

PCI:
  inherits: default
  server: 'xxxxxx'
  # port: 'xxxxx'
  database: 'xxxxx'
  trustedconnection: 'xxxx'

Azure:
  inherits: default
  server: 'xxxxx'
  port: 'xxxxxx'
  database: 'xxxxxx'
  encrypt: 'yes'
  trustservercertificate: 'no'
  connectiontimeout: '30'
  # authentication: 'ActiveDirectoryPassword'
  authentication: 'ActiveDirectoryIntegrated'

最佳答案

使用 OAuth token 连接到 SQL Server 需要使用 pre-connection attribute (基本上是指向 token 字符串的指针)。有一个open feature request在 odbc Github 存储库中可以找到此内容。我鼓励您对其进行投票,希望如果它足够受欢迎,它就会得到实现。

关于r - Shiny 的 Azure WebApp 作为 Azure SQL Server 的用户进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67570465/

相关文章:

r - 如何根据特定顺序对字符向量进行排序?

r - 如何将带有逗号分隔记录的向量 reshape 为纵向数据框?

r - 从地理 WGS84 到 R 中墨卡托的项目 - 点不有限

sql-server - 如何使用Golang SDK查询RDS的任何表格

sql-server - 在 sql server 中搜索 varchar 列的最佳方法

sql - 如何将文件批量插入到文件名是变量的*临时*表中?

python - 如何使用参数调用管道

azure - U-Sql 是否支持游标来迭代数据集并根据行值提取更多数据?

azure - 访问代理/防火墙后面的 Azure 虚拟机

r - 插入符中的 rfeControl 函数是否会创建分层折叠?