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

React应用通过MSAL对接ASP.NET Core API的Azure AD认证咨询

Hey there! Let's break down your problem step by step since you're new to React and MSAL—no worries, we'll cover all the bases to get your React frontend authenticated with Azure AD and talking to your MVC API, while keeping your existing database role management intact.

整体流程 Overview

First, let's clarify the end-to-end flow so you know what's happening:

  1. User visits your React app and clicks "Login with Azure AD".
  2. React uses MSAL.js to trigger an Azure AD login popup/redirect.
  3. User logs in, Azure AD issues an Access Token for your MVC API.
  4. React receives and securely stores the token.
  5. When React calls your MVC API, it sends the token in the Authorization: Bearer <token> header.
  6. MVC validates the Azure AD token to confirm the user's identity, then fetches the user's roles from your Azure DB to enforce permissions.

React端: Configure MSAL & Handle Token Passing

First, set up MSAL in your React app to handle login and token acquisition.

1. Install MSAL Packages

Run this in your React project:

npm install @azure/msal-react @azure/msal-browser

2. Configure MSAL Instance

Create a config file to hold your Azure AD app details:

// src/authConfig.js
import { PublicClientApplication } from '@azure/msal-browser';

// Replace these values with your Azure AD app registration details
export const msalConfig = {
  auth: {
    clientId: 'YOUR_REACT_APP_CLIENT_ID', // From your SPA app registration
    authority: 'https://login.microsoftonline.com/YOUR_TENANT_ID', // Your Azure AD tenant ID
    redirectUri: 'http://localhost:3000', // Must match the redirect URI in your SPA app registration
  },
  cache: {
    cacheLocation: 'sessionStorage', // Securely store tokens
    storeAuthStateInCookie: false,
  }
};

// Configure your MVC API's scope (from your Web API app registration)
export const apiConfig = {
  scopes: ['api://YOUR_MVC_API_CLIENT_ID/access_as_user'], // Replace with your API's scope
  uri: 'http://localhost:5000/api/TestAPI' // Your MVC API endpoint
};

export const msalInstance = new PublicClientApplication(msalConfig);

3. Add Login Component

Create a simple login button to trigger Azure AD login:

// src/components/LoginButton.jsx
import { useMsal } from '@azure/msal-react';
import { apiConfig } from '../authConfig';

export const LoginButton = () => {
  const { instance } = useMsal();

  const handleLogin = async () => {
    try {
      // Trigger popup login and request API access scope
      await instance.loginPopup({
        scopes: apiConfig.scopes,
        prompt: 'select_account' // Force account selection (optional)
      });
    } catch (error) {
      console.error('Login failed:', error);
    }
  };

  return <button onClick={handleLogin}>Login with Azure AD</button>;
};

4. Call MVC API with Token

Create a helper function to fetch data from your API while attaching the token:

// src/api/apiClient.js
import { msalInstance, apiConfig } from '../authConfig';

export async function callProtectedApi() {
  // Get the currently logged-in account
  const activeAccount = msalInstance.getActiveAccount();
  if (!activeAccount) {
    throw new Error('No user logged in! Please login first.');
  }

  // Get a silent access token for the API
  const tokenResponse = await msalInstance.acquireTokenSilent({
    account: activeAccount,
    scopes: apiConfig.scopes
  });

  // Call the API with the Bearer token in headers
  const response = await fetch(apiConfig.uri, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${tokenResponse.accessToken}`,
      'Content-Type': 'application/json'
    }
  });

  if (!response.ok) {
    throw new Error(`API request failed: ${response.statusText}`);
  }

  return await response.json();
}

MVC后端: Configure Authentication & API Validation

Now update your MVC app to accept and validate Azure AD tokens, while still using your existing database for roles.

1. Update Startup.cs

First, install the Microsoft Identity Web NuGet package:

Install-Package Microsoft.Identity.Web

Then modify ConfigureServices and Configure:

// Startup.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using Microsoft.EntityFrameworkCore;

public class Startup
{
    public IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        // Keep your existing DB context to access users/roles
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        // Configure Azure AD authentication for API
        services.AddMicrosoftIdentityWebApiAuthentication(Configuration)
            .EnableTokenAcquisitionToCallDownstreamApi()
            .AddInMemoryTokenCaches();

        // Enable CORS to allow requests from your React app
        services.AddCors(options =>
        {
            options.AddPolicy("ReactCorsPolicy", policy =>
            {
                policy.WithOrigins("http://localhost:3000") // Your React app URL
                      .AllowAnyHeader()
                      .AllowAnyMethod();
            });
        });

        services.AddControllers();
        // If you still need MVC views, keep this: services.AddControllersWithViews();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        // Apply CORS policy BEFORE authentication/authorization
        app.UseCors("ReactCorsPolicy");

        app.UseAuthentication(); // Validate incoming tokens
        app.UseAuthorization(); // Enforce permissions

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            // Keep this if you need MVC views:
            // endpoints.MapControllerRoute(
            //     name: "default",
            //     pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

2. Update appsettings.json

Add Azure AD configuration to your appsettings.json:

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "Domain": "your-tenant-domain.onmicrosoft.com",
  "TenantId": "YOUR_TENANT_ID",
  "ClientId": "YOUR_MVC_API_CLIENT_ID", // From your Web API app registration
  "Audience": "api://YOUR_MVC_API_CLIENT_ID" // Must match your API's audience
}

3. Modify TestAPIController

Update your controller to validate the token, fetch the user's roles from your DB, and enforce permissions:

// Controllers/TestAPIController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;
using System.Linq;

[Authorize] // Ensures only valid Azure AD tokens are accepted
[ApiController]
[Route("api/[controller]")]
public class TestAPIController : ControllerBase
{
    private readonly ApplicationDbContext _dbContext;

    public TestAPIController(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet]
    public IActionResult GetProtectedData()
    {
        // Get the user's UPN (unique identifier from Azure AD token)
        var userUpn = User.GetUpn();
        // Alternative: Use email if that's what's stored in your DB
        // var userEmail = User.FindFirst(System.Security.Claims.ClaimTypes.Email)?.Value;

        // Fetch user from your local database
        var localUser = _dbContext.Users.FirstOrDefault(u => u.Email == userUpn);
        if (localUser == null)
        {
            return Unauthorized("User not found in local database.");
        }

        // Fetch user's roles from your DB
        var userRoles = _dbContext.UserRoles
            .Where(ur => ur.UserId == localUser.Id)
            .Join(_dbContext.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name)
            .ToList();

        // Example: Enforce role-based access
        if (!userRoles.Contains("Admin"))
        {
            return Forbid("You do not have permission to access this resource.");
        }

        return Ok(new 
        { 
            Message = "Success! You accessed the protected API.",
            UserUPN = userUpn,
            LocalRoles = userRoles
        });
    }
}

Key Details You Need to Know

Let's cover some critical points to avoid pitfalls:

  1. Azure AD App Registrations:

    • You need two separate app registrations: one for your React SPA, one for your MVC Web API.
    • For the SPA app: Add your React redirect URI (e.g., http://localhost:3000) under Authentication > SPA and enable ID/access tokens.
    • For the Web API app: Create a scope (e.g., access_as_user) under Expose an API, then go to your SPA app's API Permissions to add this scope and grant admin consent.
  2. Token Types:

    • Always use an Access Token when calling APIs (not an ID Token). ID Tokens are for authenticating users in the frontend, while Access Tokens are for authorizing API access.
  3. Role Management:

    • Since your roles are stored in your own DB, Azure AD won't include them in the token. Your MVC backend must map the Azure AD user (via UPN/email/OID) to your local user record and fetch roles from there.
  4. Token Validation:

    • The AddMicrosoftIdentityWebApiAuthentication method automatically validates the token's signature, expiration date, audience, and issuer—you don't need to write custom validation logic.
  5. CORS:

    • Don't forget to configure CORS in your MVC app to allow requests from your React domain. Without this, you'll get browser-side CORS errors.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 13:57:46