服务器端NodeJS-需要客户端Windows ID

时间:2018-12-13 11:51:39

标签: node.js reactjs active-directory

(内部网应用程序)我正在将ReactJS与NodeJS一起用作服务器端API,以访问各种资源(例如用户活动目录配置文件)。我需要与Active Directory集成,而无需提示用户提供其凭据。

使用ActiveDirectory for Node(npm i activedirectory),我可以使用以下代码使用LDAP查询AD的硬编码sAMAccountName。

ad.findUser(sAMAccountName, function(err, user) {
    if (err) {
      console.log('ERROR: ' + JSON.stringify(err));
    }

    if (!user) console.log('User: ' + sAMAccountName + ' not found.');
    else {
      thisUser = user;
    }
  });

但是我不知道的是,当他们调用API时如何获取当前用户ID。

这2个示例提供了“服务器”用户ID,而不是客户端ID:

const user = process.env;
const user = require('os').userInfo().username;

在.net中,我通常使用

进行此操作
string NTID = HttpContext.Current.User.Identity.Name;

那么在服务器上运行的NodeJS中是否可以访问客户端用户ID?

---------更新:-----------

我一直在尝试使用passport-windowsauth实施以下解决方案,但无法使其正常运行。我将web.config文件配置如下:

<iisnode watchedFiles="*.js;node_modules\*;routes\*.js;views\*.jade" promoteServerVars="LOGON_USER,AUTH_USER" />
<security>
     <authentication>
          <anonymousAuthentication enabled="true" />
          <windowsAuthentication enabled="true" />
     </authentication>
</security>

Azure配置设置为:

enter image description here

这是我单击按钮以开始认证时调用的函数:

activeDirectory = () => {
    let url = '';
    //Default to current user when in dev
    if (
      window.location.href.indexOf('localhost') > -1
    ) {
      url = 'http://localhost:5000/express-passport';
    } else {
      url = '/express-passport';
    }
    axios({
      method: "GET",
      url: url,
      withCredentials: true
    })
      .then(response => {
        console.log("Done: ", response.data);
      })
      .catch(error => {
        console.log("An error occurred - ", error);
      });
};

这是NodeJs服务器的路由代码:

const passport = require("passport");
const WindowsStrategy = require("passport-windowsauth");

module.exports = app => {
  let thisUser = {};
  passport.use(
    new WindowsStrategy(
      {
        ldap: {
          url: "ldap://somethingldap.somewhere.com/CN=,DC=,DC=,DC=,DC=",
          base: "CN=,DC=,DC=,DC=,DC=",
          bindDN: "serviceAccountDetailsHere",
          bindCredentials: "masked"
        }
      },
      function(profile, done) {
        thisUser = profile;
        console.log("Profile:", profile);
      }
    )
  );
  app.get(
    "/express-passport",
    function(req, res, next) {
      passport.authenticate("WindowsAuthentication", function(
        error,
        user,
        info
      ) {
        // log everything to console
        console.log(error);
        console.log(user);
        console.log(info);

        if (error) {
          res.status(401).send(error);
        } else if (!user) {
          res.status(401).send(info);
        } else {
          next();
        }

        res.status(401).send(info);
      })(req, res);
    },

    // function to call once successfully authenticated
    function(req, res) {
      res.status(200).send("logged in!");
    }
  );
};

现在,当页面打开时,我单击一个按钮,希望它可以进行身份​​验证。出现一个弹出窗口,要求我输入凭据,但是弹出窗口消失了,并不断出现。我显然做错了事...

3 个答案:

答案 0 :(得分:2)

您最大的问题是,如何在MacOS开发人员计算机上正常运行该问题,并将其无缝转移到Windows计算机并以相同方式工作。

node-sspi软件包可能是最简单的,但它仅适用于Windows。

我认为您最好的选择是将passport-windowsauthPassport.js模块用于LDAP,因为您可以从任何操作系统对AD进行LDAP查询。

在服务器上,将其放在IIS后面,并按照Integrated Authentication下的说明进行操作,以使用Windows身份验证设置IIS,以使用户无缝登录。

在MacOS开发机器上,您当然不能这样做。我认为您可以为MacOS做的最好的事情是要求您提供凭据。您将不得不对此进行测试。我不确定如果没有IIS,它将不会像通常那样进行身份验证挑战(我认为不会)。如果没有,您可以按照他们的Non-integrated authentication的说明创建单独的登录页面,并且只能在开发机器上使用该登录页面。

在实际调用passport.use()时,两者之间的唯一区别是integrated: false。因此,您可能会发现必须对本地开发人员和服务器进行不同的设置(希望您可以让您的代码检测到您是否在开发人员计算机上,并自动将其设置为false)。

是的,您的开发机和服务器之间的登录行为将有所不同,但是至少您应该能够按原样升级代码并使它们在两个地方都能正常工作。

答案 1 :(得分:0)

要回答您上面提到的问题But what I can't figure out, is how to pick up the current user ID when they call the API.

似乎上面的代码被包装在用作路由处理程序回调fn的函数下。这样说,我的意思是,您肯定可以使用reqres API函数自变量requestresponse

例如:-

module.exports = {
  routeHanlder: function(req, res) {
      ad.findUser(sAMAccountName, function(err, user) {
         if (err) {
           console.log('ERROR: ' + JSON.stringify(err));
         }

         if (!user) console.log('User: ' + sAMAccountName + ' not found.');
         else {
          thisUser = user;
         }
      });
  }
}

因此在上面的示例中,req参数包含您想要的所有客户端信息,例如来自请求的来源,请求标头是什么等等。

您在问题中提到,string NTID = HttpContext.Current.User.Identity.Name;通过使用HttpContext可以获取用户身份。通过使用req,您将获得客户信息。

答案 2 :(得分:0)

下面是我最终用于此的解决方案。它是2个软件包的组合-

  

express-ntlm

  

ActiveDirectory

ntlm用于从浏览器中获取用户凭据(某些用户可能会在提示时提供这些凭据)。 ntlm具有userID后,我将使用它来查询活动目录以获取该用户的更多详细信息。使用2个模块的原因是ntlm仅提供3个字段-用户名,域名和工作站。就我而言,我需要电子邮件地址,名字,姓氏等。

https://www.npmjs.com/package/express-ntlm

https://www.npmjs.com/package/activedirectory

const ntlm = require('express-ntlm');
const ActiveDirectory = require('activedirectory');

module.exports = app => {
  const config = {
    url: 'ldap://something.somewhere.com',
    baseDN: 'CN=a,DC=b,DC=c',
    username: '',
    password: ''
  };

  app.use(
    //This is for getting the users MS ID only
    ntlm()
  );

  app.get(‘/apiName/’, (req, res) => {
    let sAMAccountName = req.ntlm.UserName;
    const ad = new ActiveDirectory(config);
    var userDetails = {
      Email: '',
      FirstName: '',
      LastName: ''
    };
    ad.findUser(sAMAccountName, (err, user) => {
      if (err) {
        console.log('ERROR: ' + JSON.stringify(err));
      }

      if (!user) console.log('User: ' + sAMAccountName + ' not found.');
      else {
        userDetails.Email = user.mail;
        userDetails.FirstName = user.firstName;
        userDetails.LastName = user.lastName;
      }
      res.json(userDetails);
      res.end();
    });
    });
  });
};