使用 express-jwt 作为中间件来验证 Azure AD 颁发的令牌

Use express-jwt as middleware to verify Azure AD issued tokens

我想知道是否可以使用 express-jwt NPM 包作为中间件来验证 Azure AD 颁发的 JWT 令牌。

我们有一个用 express/node 编写的网络 API 并且想应用中间件模式来保护我们的端点并填充用户原则。

好像是:

server.use(jwt({
    audience: '{UUID}',
    issuer: 'https://sts.windows.net/{UUID}',
}).unless({path : ['/']}))

不起作用,因为它需要客户端密码,但从 AD(很像在隐式流中)令牌是通过用户交互检索的,没有客户端密码。

您可以使用 "azure-ad-jwt"。它相当简单,不需要注入中间件。当然,您可以将其作为中间步骤注入到您自己的 "middleware" 函数中。

 private verifyToken(req: any, res: any) {
        var audience = "xxxxxxxxx";
        var tenantId = "xxxxxxxxx";

        var authorization = req.headers['authorization'];
        return Rx.Observable.create((observer) => {
            if (authorization) {
                var bearer = authorization.split(" ");
                var jwtToken = bearer[1];
                if (jwtToken) {
                    aad.verify(jwtToken, { audience: audience, tenantId: tenantId }, function (err, result) {
                        if (result) {
                            observer.next(true);
                        } else {
                            res.status(401).send('That is not a valid token!');
                        }
                    })
                } else {
                    res.status(401).send('No token in header.');
                }
            } else {
                res.status(401).send('Missing authorization attribute in header.');
            }
        });
    }

express-jwt 支持 multi-tenancy,与 azure ad 完美搭配。 https://github.com/auth0/express-jwt#multi-tenancy

import _ from 'lodash';
import jwt from 'express-jwt';

const ISS = 'https://sts.windows.net/********-****-****-****-************/';
const KEYS = {}; // response.body from https://login.microsoftonline.com/common/discovery/keys
// create another task to refresh KEYS every 24 hours.

app.use('/protected', jwt({
  secret: (req, header, payload, done) => {
    const { kid } = header;
    const { iss } = payload;

    if (iss !== ISS) { // issuer filter
      return done(new Error('invalid token issuer'));
    }

    const key = _.find(KEYS, { kid });
    if (key) {
      const pem = _.get(key, 'x5c[0]');

      if (pem) {
        return done(null, `-----BEGIN CERTIFICATE-----\n${pem}\n-----END CERTIFICATE-----`);
      }
      return done(new Error('not PEM found'));
    }
    return done(new Error('invalid kid'));
  },
}), (req, res) => {
  res.json({ msg: 'if you can see it, you have a valid access_token.' });
});

app.use((err, req, res, next) => { // error handler
  res.status(401).json({ msg: err.message });
});

参考文献: