微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用NodeJS中的服务主体连接到Azure SQL,但令牌被拒绝

如何解决使用NodeJS中的服务主体连接到Azure SQL,但令牌被拒绝

我无法让我的NodeJS应用程序使用服务主体连接到Azure sql数据库。但是,当我尝试对C#代码段执行相同的操作时,效果很好。我注意到的是,两种语言的auth返回的令牌都有点不同,如果我从C#中获取正确的令牌并将其硬编码到NodeJS中,则sql连接现在可以成功。

我首先使用ms-rest-azure进行身份验证,并提供我的clientId,tenantId和clientSecret。这将返回一个有效的凭证,我将从该凭证中提取accesstoken。

然后,我使用乏味的方法尝试通过* .database.windows.net连接到Azure sql,并在配置中提供accesstoken值。

我只是获得用户''

登录失败

在ms-rest-azure登录中给我一个被Azure sql拒绝的令牌时,我在做什么错?我看到的一件事是,工作令牌的受众为 database.windows.net ,其中-来自ms-rest-azure的用户 management.core.windows.net

我已经被困了几天,如果有人在这里有任何很棒的线索。 ms-rest-azure上的文档似乎很不存在,只是为您提供了Azure销售页面解决方法

const msRestAzure = require('ms-rest-azure');
const { reject } = require('async');


let clientSecret = "xxx";
let serverName = "xxx.database.windows.net";
let databaseName = "xxx";
let clientId = "xxx";
let tenantId = "xxx";

azureCredentials = msRestAzure.loginWithServicePrincipalSecret(clientId,clientSecret,tenantId,function(err,credentials) {
    if (err) return console.log(err);
    credentials.getToken((err,results) => {
        if(err) return reject(err);
        
        let accesstoken = results.accesstoken;

        var Connection = require('tedious').Connection;
        var Request = require('tedious').Request;

        var config = {
            server: serverName,authentication: {
                type: 'azure-active-directory-access-token',options: {
                    token: accesstoken
                }
            },options: {
                debug: {
                packet: true,data: true,payload: true,token: false,log: true
                },database: databaseName,encrypt: true
            }  
        };

        var connection = new Connection(config);

        connection.connect();

        connection.on('connect',function(err) {
            if(err) {
                console.log(err);
            }
            executeStatement();
        }
        );

        connection.on('debug',function(text) {
            console.log(text);
        }
        );

        function executeStatement() {
        request = new Request("select * from Text",rowCount) {
            if (err) {
            console.log(err);
            } else {
            console.log(rowCount + ' rows');
            }

            connection.close();
        });

        request.on('row',function(columns) {
            columns.forEach(function(column) {
            if (column.value === null) {
                console.log('NULL');
            } else {
                console.log(column.value);
            }
            });
        });

        request.on('done',function(rowCount,more) {
            console.log(rowCount + ' rows returned');
        });

        connection.execsql(request);
        }
    });   
})

解决方法

当我们使用软件包ms-rest-azure中的证书获取令牌时,默认情况下,令牌的访问者为https://management.core.windows.net/,它只能用于调用Azure rest api。如果我们要使用Azure AD令牌连接sql,则令牌的访问者应为https://database.windows.net/。因此,我们应该更新用于获取令牌的代码

msrestAzure.loginWithServicePrincipalSecret(
    clientId,clientSecret,tenantId,{
      tokenAudience: "https://database.windows.net/",},

例如

  1. 创建服务主体
az login
az ad sp create-for-rbac -n 'MyApp' --skip-assignment
  1. 配置SQL数据库

a。 Use your Azure Sql AD admin to connect Azure SQL vai SSMS

b。将服务主体添加到您需要使用的数据库中

create user [<Azure_AD_principal_name>] from external provider
ALTER ROLE db_owner ADD MEMBER [<Azure_AD_principal_name>]
     
  1. 代码
var msrestAzure = require("ms-rest-azure");
var { Connection,Request } = require("tedious");

let clientSecret = "xxx";
let serverName = "xxx.database.windows.net";
let databaseName = "xxx";
let clientId = "xxx";
let tenantId = "xxx";

async function getConnect() {
  // way for Azure Service Principal
  let databaseCredentials = await msrestAzure.loginWithServicePrincipalSecret(
    clientId,);

  // getting access token
  let databaseAccessToken = await new Promise((resolve,reject) => {
    databaseCredentials.getToken((err,results) => {
      if (err) return reject(err);
      resolve(results.accessToken);
    });
  });
  var config = {
    server: serverName,authentication: {
      type: "azure-active-directory-access-token",options: {
        token: databaseAccessToken,options: {
      debug: {
        packet: true,data: true,payload: true,token: false,log: true,database: databaseName,encrypt: true,};

  var connection = new Connection(config);
  connection.connect();
  connection.on("connect",function (err) {
    if (err) {
      console.log(err);
    }
    executeStatement(connection);
  });

  connection.on("debug",function (text) {
    console.log(text);
  });
}
function executeStatement(connection) {
  request = new Request("select * from CSVTest",function (err,rowCount) {
    if (err) {
      console.log(err);
    } else {
      console.log(rowCount + " rows");
    }

    connection.close();
  });

  request.on("row",function (columns) {
    columns.forEach(function (column) {
      if (column.value === null) {
        console.log("NULL");
      } else {
        console.log(column.value);
      }
    });
  });

  request.on("done",function (rowCount,more) {
    console.log(rowCount + " rows returned");
  });

  connection.execSql(request);
}

getConnect()
  .then(() => {
    console.log("run successfully");
  })
  .catch((err) => {
    console.log(err);
  });

enter image description here

有关更多详细信息,请参阅here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。