如何配置.net core angular azure AD 身份验证?
How to configure .net core angular azure AD authentication?
我目前正在将 Azure AD 身份验证集成到 Angular - .Net 核心 3.1 项目。这是一个从 Visual Studio 2019 模板(ASP.NET Core Web App)生成的项目。
在 Azure 门户中,我注册了 2 个应用程序并按 MS tutorial and this.
配置
两个注册的应用程序:
- frontend_app(客户端 ID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx16e3)
- backend_api(客户端 ID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxfcc1)
但是我只发布了一个App服务,里面同时包含SPA和API。登录后,我得到了一个令牌,它附加到使用 MSAL 拦截器的每个 api 调用。
问题是所有呼叫 return 都是:401,由于 'audience is invalid'。在身份验证令牌中,观众重视 frontend_app.
的客户端 ID
如何解决接受观众?
只为一项应用服务使用 2 个应用注册是否正确?
正如我在评论中所说,401错误通常是因为您的受众与您要调用的api不匹配,因此您需要确保您的目标受众是您的api,你的问题中应该是你的backend_api,我用auth code flow给你做一个简单的演示:
获取令牌:
解析token:
我遇到了和你一样的问题,相信我已经找到了解决办法。我最初遵循的所有指南都使用隐式流程。正如 Carl 在他的回答中指出的那样(我认为这没有正确解决您的问题),有一个 auth flow which is the recommended way to go. Unfortunately the standard MSAL libraries from all the samples and guides are 1.x and don't support auth flow. Instead, you'll need to use MSAL.js 2.0. The catch is that the angular library is still in alpha
所以,这就是我为使一切顺利进行所做的工作。我正在使用 Angular 10 前端和 ASP.NET Core 3.1 后端。
首先,您创建后端 api 应用程序注册(您可能不需要更改)。这是相关文档:Register Web API。重要提示:
- 使用此方法,您无需将前端客户端 ID 添加为 'Expose an API' 部分下的授权应用程序。我们将使用身份验证流程以不同方式处理。
- 不需要重定向 URI,因为您的后端不会让用户登录
- 您至少需要一台示波器才能正常工作
然后按照 MSAL.js 2.0 文档创建前端应用程序注册。重要说明如下:
- 确保您 select SPA 平台并输入有效的重定向 URI
- 不要选中 'Implicit Grant'
的复选框
- 在 'API permissions' 下,让您的前端应用程序访问您的后端 api:
- 在 'API permissions' 下单击 'Add permission',然后单击 'My APIs' 选项卡
- 找到您的后端应用程序和select适当的范围。
- 点击'Add permissions'
- 选择性地同意您的 API
您的应用注册应类似于以下内容:
backend app registration expose an api
frontend app registration authentication
frontend app registration api permissions
现在是代码。对于您的 angular 应用程序,首先安装必要的模块:
npm install @azure/msal-browser @azure/msal-angular@alpha
然后将其添加到您的应用程序模块中:
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { tap } from 'rxjs/operators';
import {
IPublicClientApplication,
PublicClientApplication,
InteractionType,
BrowserCacheLocation,
LogLevel,
} from '@azure/msal-browser';
import {
MsalGuard,
MsalInterceptor,
MsalBroadcastService,
MsalInterceptorConfiguration,
MsalModule,
MsalService,
MSAL_GUARD_CONFIG,
MSAL_INSTANCE,
MSAL_INTERCEPTOR_CONFIG,
MsalGuardConfiguration,
} from '@azure/msal-angular';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
const PROTECTED_RESOURCE_MAP: Map<string, Array<string>> = new Map([
['https://graph.microsoft.com/v1.0/me', ['user.read']],
[
'api/admin/users',
['api://<backend app id>/access_as_admin'],
],
]);
const IS_IE =
window.navigator.userAgent.indexOf('MSIE ') > -1 ||
window.navigator.userAgent.indexOf('Trident/') > -1;
export function loggerCallback(logLevel, message) {
console.log(message);
}
export function MSALInstanceFactory(): IPublicClientApplication {
return new PublicClientApplication({
auth: {
clientId: '<frontend app id>',
authority:
'https://login.microsoftonline.com/<azure ad tenant id>',
redirectUri: 'http://localhost:4200',
postLogoutRedirectUri: 'http://localhost:4200/#/logged-out',
},
cache: {
cacheLocation: BrowserCacheLocation.LocalStorage,
storeAuthStateInCookie: IS_IE, // set to true for IE 11
},
system: {
loggerOptions: {
loggerCallback,
logLevel: LogLevel.Verbose,
piiLoggingEnabled: false,
},
},
});
}
export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
return {
interactionType: InteractionType.Redirect,
protectedResourceMap: PROTECTED_RESOURCE_MAP,
};
}
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
return {
interactionType: InteractionType.Redirect,
};
}
export function initializeApp(appConfig: AppConfigService) {
const promise = appConfig
.loadAppConfig()
.pipe(tap((settings: IAppConfig) => {}))
.toPromise();
return () => promise;
}
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
HttpClientModule,
MsalModule,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
},
{
provide: MSAL_INSTANCE,
useFactory: MSALInstanceFactory,
},
{
provide: MSAL_GUARD_CONFIG,
useFactory: MSALGuardConfigFactory,
},
{
provide: MSAL_INTERCEPTOR_CONFIG,
useFactory: MSALInterceptorConfigFactory,
},
MsalService,
MsalGuard,
MsalBroadcastService,
],
bootstrap: [AppComponent],
})
export class AppModule {}
然后你可以简单地将 MsalGuard
扔到任何你想保护的路线上。
对于后端,首先安装Microsoft.Identity.Web包:
dotnet add package Microsoft.Identity.Web --version 1.3.0
这是我的Startup.cs中的相关代码:
public void ConfigureServices(IServiceCollection services)
{
// other stuff...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
})
.AddInMemoryTokenCaches();
services.AddCors((options =>
{
options.AddPolicy("FrontEnd", builder =>
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
}));
// other stuff...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// other stuff...
app.UseCors("FrontEnd");
app.UseAuthentication();
app.UseAuthorization();
// other stuff...
}
appsettings.json 包含:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<azure ad domain>",
"TenantId": "<azure ad tenant id>",
"ClientId": "<backend app id>"
}
我目前正在将 Azure AD 身份验证集成到 Angular - .Net 核心 3.1 项目。这是一个从 Visual Studio 2019 模板(ASP.NET Core Web App)生成的项目。
在 Azure 门户中,我注册了 2 个应用程序并按 MS tutorial and this.
两个注册的应用程序:
- frontend_app(客户端 ID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx16e3)
- backend_api(客户端 ID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxfcc1)
但是我只发布了一个App服务,里面同时包含SPA和API。登录后,我得到了一个令牌,它附加到使用 MSAL 拦截器的每个 api 调用。
问题是所有呼叫 return 都是:401,由于 'audience is invalid'。在身份验证令牌中,观众重视 frontend_app.
的客户端 ID如何解决接受观众? 只为一项应用服务使用 2 个应用注册是否正确?
正如我在评论中所说,401错误通常是因为您的受众与您要调用的api不匹配,因此您需要确保您的目标受众是您的api,你的问题中应该是你的backend_api,我用auth code flow给你做一个简单的演示:
获取令牌:
解析token:
我遇到了和你一样的问题,相信我已经找到了解决办法。我最初遵循的所有指南都使用隐式流程。正如 Carl 在他的回答中指出的那样(我认为这没有正确解决您的问题),有一个 auth flow which is the recommended way to go. Unfortunately the standard MSAL libraries from all the samples and guides are 1.x and don't support auth flow. Instead, you'll need to use MSAL.js 2.0. The catch is that the angular library is still in alpha
所以,这就是我为使一切顺利进行所做的工作。我正在使用 Angular 10 前端和 ASP.NET Core 3.1 后端。
首先,您创建后端 api 应用程序注册(您可能不需要更改)。这是相关文档:Register Web API。重要提示:
- 使用此方法,您无需将前端客户端 ID 添加为 'Expose an API' 部分下的授权应用程序。我们将使用身份验证流程以不同方式处理。
- 不需要重定向 URI,因为您的后端不会让用户登录
- 您至少需要一台示波器才能正常工作
然后按照 MSAL.js 2.0 文档创建前端应用程序注册。重要说明如下:
- 确保您 select SPA 平台并输入有效的重定向 URI
- 不要选中 'Implicit Grant' 的复选框
- 在 'API permissions' 下,让您的前端应用程序访问您的后端 api:
- 在 'API permissions' 下单击 'Add permission',然后单击 'My APIs' 选项卡
- 找到您的后端应用程序和select适当的范围。
- 点击'Add permissions'
- 选择性地同意您的 API
您的应用注册应类似于以下内容:
backend app registration expose an api
frontend app registration authentication
frontend app registration api permissions
现在是代码。对于您的 angular 应用程序,首先安装必要的模块:
npm install @azure/msal-browser @azure/msal-angular@alpha
然后将其添加到您的应用程序模块中:
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { tap } from 'rxjs/operators';
import {
IPublicClientApplication,
PublicClientApplication,
InteractionType,
BrowserCacheLocation,
LogLevel,
} from '@azure/msal-browser';
import {
MsalGuard,
MsalInterceptor,
MsalBroadcastService,
MsalInterceptorConfiguration,
MsalModule,
MsalService,
MSAL_GUARD_CONFIG,
MSAL_INSTANCE,
MSAL_INTERCEPTOR_CONFIG,
MsalGuardConfiguration,
} from '@azure/msal-angular';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
const PROTECTED_RESOURCE_MAP: Map<string, Array<string>> = new Map([
['https://graph.microsoft.com/v1.0/me', ['user.read']],
[
'api/admin/users',
['api://<backend app id>/access_as_admin'],
],
]);
const IS_IE =
window.navigator.userAgent.indexOf('MSIE ') > -1 ||
window.navigator.userAgent.indexOf('Trident/') > -1;
export function loggerCallback(logLevel, message) {
console.log(message);
}
export function MSALInstanceFactory(): IPublicClientApplication {
return new PublicClientApplication({
auth: {
clientId: '<frontend app id>',
authority:
'https://login.microsoftonline.com/<azure ad tenant id>',
redirectUri: 'http://localhost:4200',
postLogoutRedirectUri: 'http://localhost:4200/#/logged-out',
},
cache: {
cacheLocation: BrowserCacheLocation.LocalStorage,
storeAuthStateInCookie: IS_IE, // set to true for IE 11
},
system: {
loggerOptions: {
loggerCallback,
logLevel: LogLevel.Verbose,
piiLoggingEnabled: false,
},
},
});
}
export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
return {
interactionType: InteractionType.Redirect,
protectedResourceMap: PROTECTED_RESOURCE_MAP,
};
}
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
return {
interactionType: InteractionType.Redirect,
};
}
export function initializeApp(appConfig: AppConfigService) {
const promise = appConfig
.loadAppConfig()
.pipe(tap((settings: IAppConfig) => {}))
.toPromise();
return () => promise;
}
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
HttpClientModule,
MsalModule,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
},
{
provide: MSAL_INSTANCE,
useFactory: MSALInstanceFactory,
},
{
provide: MSAL_GUARD_CONFIG,
useFactory: MSALGuardConfigFactory,
},
{
provide: MSAL_INTERCEPTOR_CONFIG,
useFactory: MSALInterceptorConfigFactory,
},
MsalService,
MsalGuard,
MsalBroadcastService,
],
bootstrap: [AppComponent],
})
export class AppModule {}
然后你可以简单地将 MsalGuard
扔到任何你想保护的路线上。
对于后端,首先安装Microsoft.Identity.Web包:
dotnet add package Microsoft.Identity.Web --version 1.3.0
这是我的Startup.cs中的相关代码:
public void ConfigureServices(IServiceCollection services)
{
// other stuff...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
})
.AddInMemoryTokenCaches();
services.AddCors((options =>
{
options.AddPolicy("FrontEnd", builder =>
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
}));
// other stuff...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// other stuff...
app.UseCors("FrontEnd");
app.UseAuthentication();
app.UseAuthorization();
// other stuff...
}
appsettings.json 包含:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<azure ad domain>",
"TenantId": "<azure ad tenant id>",
"ClientId": "<backend app id>"
}