You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何验证Angular应用(Azure AD/MSAL)登录后调用NodeJS API的令牌?

Angular + Azure AD 令牌传参及 Node.js 后端验证方案

一、Angular 前端自动携带 Access Token 到请求头

用 HTTP 拦截器统一处理,避免每个请求手动添加令牌:

  1. 新建拦截器文件 auth.interceptor.ts:
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, from } from 'rxjs';
import { MsalService } from '@azure/msal-angular';
import { mergeMap } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private msalService: MsalService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    // 仅给后端API请求添加令牌,排除登录/第三方请求
    if (request.url.startsWith('/api')) {
      return from(this.msalService.acquireTokenSilent({
        scopes: ['api://{你的后端API Client ID}/access_as_user'], // 替换为Azure AD中注册的API权限
        account: this.msalService.instance.getActiveAccount()!
      })).pipe(
        mergeMap(tokenResponse => {
          const authReq = request.clone({
            setHeaders: {
              Authorization: `Bearer ${tokenResponse.accessToken}`
            }
          });
          return next.handle(authReq);
        })
      );
    }
    return next.handle(request);
  }
}
  1. 在 app.module.ts 中注册拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ]
})
export class AppModule { }

注意:scopes 必须与你在 Azure AD 中为后端API注册的权限一致,否则无法获取有效访问令牌。

二、Node.js 后端验证 Azure AD Access Token

用 jsonwebtoken 结合 jwks-rsa 实现验证中间件,自动校验令牌合法性:

  1. 安装依赖:
npm install jsonwebtoken jwks-rsa
  1. 编写验证中间件 auth.middleware.js:
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
  jwksUri: 'https://login.microsoftonline.com/{你的租户ID}/discovery/v2.0/keys' // 替换为你的Azure租户ID
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, function(err, key) {
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

function validateToken(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ message: '未提供有效令牌' });
  }

  const token = authHeader.split(' ')[1];

  jwt.verify(token, getKey, {
    audience: 'api://{你的后端API Client ID}', // 替换为后端API的Client ID
    issuer: 'https://login.microsoftonline.com/{你的租户ID}/v2.0', // 替换为你的Azure租户ID
    algorithms: ['RS256']
  }, function(err, decoded) {
    if (err) {
      return res.status(403).json({ message: '令牌验证失败', error: err.message });
    }
    // 将解码后的用户信息挂载到req对象,后续接口可直接调用
    req.user = decoded;
    next();
  });
}

module.exports = validateToken;
  1. 在 Express 路由中使用中间件:
const express = require('express');
const validateToken = require('./auth.middleware');
const router = express.Router();

// 受保护的API接口,必须经过令牌验证
router.get('/api/protected', validateToken, (req, res) => {
  res.json({ 
    message: '访问受保护接口成功',
    user: req.user
  });
});

module.exports = router;

关键注意事项

  • 不要用 ID Token 调用 API:ID Token 仅用于前端验证用户身份,Access Token 才是后端 API 的合法凭证。
  • 权限配置匹配:前端请求的 scope 必须与后端 API 在 Azure AD 中注册的权限完全一致,否则会因 audience 不匹配导致验证失败。
  • 占位符替换:所有 {你的租户ID}、{你的后端API Client ID} 需替换为 Azure AD 中的实际值。
  • 令牌自动刷新:前端拦截器中的 acquireTokenSilent 会自动刷新过期令牌,无需手动处理。

内容的提问来源于stack exchange,提问作者user68288

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:35:22