如何配置 React 客户端、.NET Core 3.1 后端、单租户 SSO

How to Configure React Client, .NET Core 3.1 Backend, Single Tenant SSO

我想知道这是否可能?

我的整个 API 都锁定在 [Authorize] 标签后面。

我的启动 class 配置如下:

using Application.TestEntities;
using FluentValidation.AspNetCore;
using MediatR;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Persistence;

namespace API
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<DataContext>(opt =>
            {
                opt.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
            });
            services.AddCors(opt =>
            {
                opt.AddPolicy("CorsPolicy", policy =>
                {
                    policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000");
                });
            });
            services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
                .AddAzureADBearer(opt => Configuration.Bind("AzureAd", opt));

            services.AddMediatR(typeof(List.Handler).Assembly);
            services.AddControllers().AddFluentValidation(cfg => cfg.RegisterValidatorsFromAssemblyContaining<Create>());
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseMiddleware<ErrorHandlingMiddleware>();
            if (env.IsDevelopment())
            {
                // app.UseDeveloperExceptionPage();
            }

            app.UseCors("CorsPolicy");

            app.UseRouting();

            app.UseAuthentication();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

我的 appsettings.json 这样设置:

{
  "ConnectionStrings": {
    "DefaultConnection": "Data source = blahblah.db"
  },
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<MyTenantId>",
    "ClientId": "<MyClientId>"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

在客户端,我在 index.tsx:

中使用 react-aad-msal
import React from "react";
import ReactDOM from "react-dom";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
import "react-toastify/dist/ReactToastify.min.css";
import "react-widgets/dist/css/react-widgets.css";
import "./app/layout/styles.css";
import App from "./app/layout/App";
import * as serviceWorker from "./serviceWorker";
import ScrollToTop from "./app/layout/ScrollToTop";
import dateFnsLocalizer from "react-widgets-date-fns";
import { AzureAD } from "react-aad-msal";
import { authProvider } from "./app/common/util/authProvider";

new dateFnsLocalizer();

export const history = createBrowserHistory();

ReactDOM.render(
  // <React.StrictMode>
  <AzureAD provider={authProvider} forceLogin={true}>
    <Router history={history}>
      <ScrollToTop>
        <App />
      </ScrollToTop>
    </Router>
  </AzureAD>,
  // </React.StrictMode>,
  document.getElementById("root")
);

serviceWorker.unregister();

authProvider.ts:

import { MsalAuthProvider, LoginType } from "react-aad-msal";

const config = {
  auth: {
    authority:
      "https://login.microsoftonline.com/<MyTenantId>",
    clientId: "<MyClientId>",
    redirectUri: "http://localhost:3000",
  },
  cache: {
    cacheLocation: "localStorage" as
      | "localStorage"
      | "sessionStorage"
      | undefined,
    storeAuthStateInCookie: true,
  },
};

export const authenticationParameters = {
  scopes: ["<WhatDoIEvenPutHere?>"],
};

const options = {
  loginType: LoginType.Redirect,
  tokenRefreshUri: window.location.origin,
};

export const authProvider = new MsalAuthProvider(
  config,
  authenticationParameters,
  options
);

目标是让我的 API 和我的 React 应用程序锁定在 Azure AD 身份验证之后,这样您就必须在我的租户上才能访问它们中的任何一个。 用户将通过客户端中的组件重定向到 Microsoft 登录页面。登录后,他们将获得对 React 应用程序以及 API 端点的访问权限。

问题是,这可能吗?注册如何在 Azure 中工作?一份为客户注册,另一份为 API?还是两个应用程序都引用的一个注册?范围呢?公开 API?

编辑:

我...想我明白了吗?

在 Azure 中注册一次。

使用 http://localhost:3000 作为重定向 URI 验证为 SPA。 检查隐式授权下的“访问令牌”和“ID 令牌”。

使用 App ID URI“api://(guid)”公开 API 添加范围:随便命名 - 我使用“api”,所以它显示为“api://(guid)/api”

API 权限 -> 添加权限 -> MY APIs -> select 应用程序并检查您之前添加的范围。

然后在你的 authProvider.ts 中输入范围:["(guid)/(YourScopeName)"],所以我的是 ["(guid)/api"]

它现在似乎可以正常工作了。在邮递员中,我可以输入从登录中取回的不记名令牌,然后取回数据,当我禁用它时,我会取回 401。这正是我一直在寻找的东西。

对于任何阅读本文的人,如果我做错了什么或不明智的事情,请告诉我。

来自我对原文的编辑post:

在 Azure 中注册一次。

使用 http://localhost:3000 作为重定向 URI 验证为 SPA。检查隐式授权下的“访问令牌”和“ID 令牌”。

使用 App ID URI“api://(guid)”公开一个 API 添加范围:随意命名 - 我使用了“api”,所以它显示向上为“api://(guid)/api”

API 权限 -> 添加权限 -> MY APIs -> select 应用程序并检查您之前添加的范围。

然后在你的 authProvider.ts 中输入范围:["(guid)/(YourScopeName)"],所以我的是 ["(guid)/api"]