不记名令牌失败 - 关联失败 - 未找到 Cookie
Bearer Token Fails - Correlation Failed - Cookie Not Found
我正在尝试使用 Angular 前端和核心 MVC API 实现 Microsoft 的 MSAL。
我已经能够在 Angular 应用程序上成功进行身份验证并调用 Graph API 端点。 Angular 应用程序使用以下代码:
app.module.ts
@NgModule({
declarations: [...],
imports: [
...
MsalModule.forRoot(
new PublicClientApplication({
auth: {
clientId: '47...',
authority: 'https://login.microsoftonline.com/6d...',
redirectUri: 'https://localhost:4200',
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
},
}),
{
interactionType: InteractionType.Redirect,
authRequest: { scopes: ['user.read'] },
},
{
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['https://localhost:44333/Auth/Index', ['user.read']]
]),
},
),
RouterModule,
],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
}],
bootstrap: [AppComponent, MsalRedirectComponent],
})
export class AppModule {}
我可以通过将 HttpClient 与配置的 MsalInterceptor
一起使用来成功调用图 API
this.http.get('https://graph.microsoft.com/v1.0/me')
.subscribe(profile => { this.profile = profile; });
接下来我尝试用类似的代码调用我自己的 API
this.http.get('https://localhost:44333/Auth/Index')
.subscribe(token => { this.token = token; });
但是,此请求失败并出现以下错误:
An unhandled exception occurred while processing the request.
Exception: Correlation failed.
Unknown location
Exception: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler.HandleRequestAsync()
我假设问题出在我的 API 上。我在我的 .Net 5.0 MVC API 中配置了身份验证,如下所示:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddOptions();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new[] { "user.read" })
.AddInMemoryTokenCaches();
}
appsettings.json
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com",
"TenantId": "6d...",
"ClientId": "47...",
"ClientSecret": "..."
},
}
AuthController.cs
namespace Auth.Services
{
[Route("{controller}/{action}")]
[Authorize]
public class AuthController : Controller
{
private readonly ITokenAcquisition tokenAcquisition;
public AuthController(ITokenAcquisition tokenAcquisition) => this.tokenAcquisition = tokenAcquisition;
[HttpGet]
public async Task<IActionResult> Index()
{
var scopes = new string[] { "user.read" };
var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);
//...
return Ok(...);
}
}
}
应用程序似乎从未到达控制器。 None 的断点曾经被击中,当我检查事件时,抛出了两个异常:
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Warning: '.AspNetCore.Correlation.XXX' cookie not found.
System.Exception: An error was encountered while handling the remote login.
---> System.Exception: Correlation failed.
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
我感兴趣的部分是“未找到 cookie”异常。我发送的不是 cookie,而是 Bearer Token。
我的猜测是我的 API 配置中缺少某些东西会告诉中间件查找 Bearer 令牌而不是 cookie。但是,当我尝试将中间件配置为使用 AddJwtBearer(...)
时,我遇到了一系列全新的错误。所以问题是,要从 Angular 前端获取身份验证 MSAL 令牌以在 API 后端工作,我缺少什么?
@weichch 的评论让我走上了正确的道路,但是这个例子使用了过时的代码。我需要做的就是将我的 Startup.cs 文件更改为类似于以下内容:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddOptions();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
// Note: the middleware is Api not App... I accidentally called App, and it took
// me a minute to realize my mistake.
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
services.AddControllers();
}
我的 Angular 申请中也有错误需要更正。我的 API 的范围需要更改为我在 Azure 门户 'api://47.../access_as_user'
中注册的 API 在更改范围之前,我收到“Bearer error=invalid_token” , error_description="签名无效""错误。因此,app.module.ts 类似于以下内容:
@NgModule({
declarations: [...],
imports: [
...
MsalModule.forRoot(
new PublicClientApplication({
auth: {
clientId: '47...',
authority: 'https://login.microsoftonline.com/6d...',
redirectUri: 'https://localhost:4200',
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
},
}),
{
interactionType: InteractionType.Redirect,
// !!! Changed Here !!!
authRequest: { scopes: ['user.read', 'api://47.../access_as_user'] },
},
{
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['https://graph.microsoft.com/v1.0/me', ['user.read']],
// !!! Changed Here !!!
['https://localhost:44333/Auth/Index', ['api://47.../access_as_user']]
]),
},
),
RouterModule,
],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
}],
bootstrap: [AppComponent, MsalRedirectComponent],
})
export class AppModule {}
我正在尝试使用 Angular 前端和核心 MVC API 实现 Microsoft 的 MSAL。
我已经能够在 Angular 应用程序上成功进行身份验证并调用 Graph API 端点。 Angular 应用程序使用以下代码:
app.module.ts
@NgModule({
declarations: [...],
imports: [
...
MsalModule.forRoot(
new PublicClientApplication({
auth: {
clientId: '47...',
authority: 'https://login.microsoftonline.com/6d...',
redirectUri: 'https://localhost:4200',
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
},
}),
{
interactionType: InteractionType.Redirect,
authRequest: { scopes: ['user.read'] },
},
{
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['https://localhost:44333/Auth/Index', ['user.read']]
]),
},
),
RouterModule,
],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
}],
bootstrap: [AppComponent, MsalRedirectComponent],
})
export class AppModule {}
我可以通过将 HttpClient 与配置的 MsalInterceptor
一起使用来成功调用图 APIthis.http.get('https://graph.microsoft.com/v1.0/me')
.subscribe(profile => { this.profile = profile; });
接下来我尝试用类似的代码调用我自己的 API
this.http.get('https://localhost:44333/Auth/Index')
.subscribe(token => { this.token = token; });
但是,此请求失败并出现以下错误:
An unhandled exception occurred while processing the request. Exception: Correlation failed. Unknown location Exception: An error was encountered while handling the remote login. Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler.HandleRequestAsync()
我假设问题出在我的 API 上。我在我的 .Net 5.0 MVC API 中配置了身份验证,如下所示:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddOptions();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new[] { "user.read" })
.AddInMemoryTokenCaches();
}
appsettings.json
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com",
"TenantId": "6d...",
"ClientId": "47...",
"ClientSecret": "..."
},
}
AuthController.cs
namespace Auth.Services
{
[Route("{controller}/{action}")]
[Authorize]
public class AuthController : Controller
{
private readonly ITokenAcquisition tokenAcquisition;
public AuthController(ITokenAcquisition tokenAcquisition) => this.tokenAcquisition = tokenAcquisition;
[HttpGet]
public async Task<IActionResult> Index()
{
var scopes = new string[] { "user.read" };
var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);
//...
return Ok(...);
}
}
}
应用程序似乎从未到达控制器。 None 的断点曾经被击中,当我检查事件时,抛出了两个异常:
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Warning: '.AspNetCore.Correlation.XXX' cookie not found.
System.Exception: An error was encountered while handling the remote login. ---> System.Exception: Correlation failed. --- End of inner exception stack trace --- at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync() at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
我感兴趣的部分是“未找到 cookie”异常。我发送的不是 cookie,而是 Bearer Token。
我的猜测是我的 API 配置中缺少某些东西会告诉中间件查找 Bearer 令牌而不是 cookie。但是,当我尝试将中间件配置为使用 AddJwtBearer(...)
时,我遇到了一系列全新的错误。所以问题是,要从 Angular 前端获取身份验证 MSAL 令牌以在 API 后端工作,我缺少什么?
@weichch 的评论让我走上了正确的道路,但是这个例子使用了过时的代码。我需要做的就是将我的 Startup.cs 文件更改为类似于以下内容:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddOptions();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
// Note: the middleware is Api not App... I accidentally called App, and it took
// me a minute to realize my mistake.
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
services.AddControllers();
}
我的 Angular 申请中也有错误需要更正。我的 API 的范围需要更改为我在 Azure 门户 'api://47.../access_as_user'
中注册的 API 在更改范围之前,我收到“Bearer error=invalid_token” , error_description="签名无效""错误。因此,app.module.ts 类似于以下内容:
@NgModule({
declarations: [...],
imports: [
...
MsalModule.forRoot(
new PublicClientApplication({
auth: {
clientId: '47...',
authority: 'https://login.microsoftonline.com/6d...',
redirectUri: 'https://localhost:4200',
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
},
}),
{
interactionType: InteractionType.Redirect,
// !!! Changed Here !!!
authRequest: { scopes: ['user.read', 'api://47.../access_as_user'] },
},
{
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['https://graph.microsoft.com/v1.0/me', ['user.read']],
// !!! Changed Here !!!
['https://localhost:44333/Auth/Index', ['api://47.../access_as_user']]
]),
},
),
RouterModule,
],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true,
}],
bootstrap: [AppComponent, MsalRedirectComponent],
})
export class AppModule {}