如何配置 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"]
我想知道这是否可能?
我的整个 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-msalimport 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"]