【发布时间】:2021-11-12 12:45:54
【问题描述】:
我正在尝试在我的容器化 ASP.NET WebAPI 项目中使用设备代码身份验证。当我在 docker 之外运行应用程序时一切正常,但是当应用程序在 docker 容器中运行时出现以下错误:
Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HMBPTCKK2U5R", Request id "0HMBPTCKK2U5R:00000002": An unhandled exception was thrown by the application.
MSAL.NetCore.4.36.0.0.MsalServiceException:
ErrorCode: invalid_client
Microsoft.Identity.Client.MsalServiceException: A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Trace ID: 79b92211-930d-41a2-9bf7-af89711cbe00
Correlation ID: 7e73cb95-1e9c-4a28-ab66-0672aa3e9e1c
Timestamp: 2021-09-17 14:56:50Z
at Microsoft.Identity.Client.OAuth2.OAuth2Client.ThrowServerException(HttpResponse response, RequestContext requestContext)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.CreateResponse[T](HttpResponse response, RequestContext requestContext)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.ExecuteRequestAsync[T](Uri endPoint, HttpMethod method, RequestContext requestContext, Boolean expectErrorsOn200OK, Boolean addCommonHeaders)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.GetTokenAsync(Uri endPoint, RequestContext requestContext, Boolean addCommonHeaders)
at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint, ICoreLogger logger)
at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint, ICoreLogger logger)
at Microsoft.Identity.Client.OAuth2.TokenClient.SendTokenRequestAsync(IDictionary`2 additionalBodyParameters, String scopeOverride, String tokenEndpointOverride, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.DeviceCodeRequest.WaitForTokenResponseAsync(DeviceCodeResult deviceCodeResult, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.DeviceCodeRequest.WaitForTokenResponseAsync(DeviceCodeResult deviceCodeResult, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.DeviceCodeRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.PublicClientExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenWithDeviceCodeParameters deviceCodeParameters, CancellationToken cancellationToken)
at Elicity.Ampere.Logic.Authentication.DeviceCodeAuthenticationLogic.GetTokenForWebApiUsingDeviceCodeFlowAsync(IEnumerable`1 scopes, Action`1 deviceCodeCallback) in /app/Logic/Logic.Authentication/DeviceCodeAuthenticationLogic.cs:line 109
at Elicity.Ampere.Logic.Authentication.DeviceCodeAuthenticationLogic.AcquireATokenFromCacheOrDeviceCodeFlowAsync(IEnumerable`1 scopes, Boolean interactive, Action`1 deviceCodeCallback) in /app/Logic/Logic.Authentication/DeviceCodeAuthenticationLogic.cs:line 78
at Elicity.Ampere.Service.Authentication.AuthenticationController.Get() in /app/Services/Service.Authentication/Controllers/AuthenticationController.cs:line 65
at lambda_method7(Closure , Object )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
StatusCode: 401
ResponseBody: {"error":"invalid_client","error_description":"AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.\r\nTrace ID: 79b92211-930d-41a2-9bf7-af89711cbe00\r\nCorrelation ID: 7e73cb95-1e9c-4a28-ab66-0672aa3e9e1c\r\nTimestamp: 2021-09-17 14:56:50Z","error_codes":[7000218],"timestamp":"2021-09-17 14:56:50Z","trace_id":"79b92211-930d-41a2-9bf7-af89711cbe00","correlation_id":"7e73cb95-1e9c-4a28-ab66-0672aa3e9e1c","error_uri":"https://login.microsoftonline.com/error?code=7000218"}
Headers: Cache-Control: no-store, no-cache
Pragma: no-cache
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
client-request-id: 7e73cb95-1e9c-4a28-ab66-0672aa3e9e1c
x-ms-request-id: 79b92211-930d-41a2-9bf7-af89711cbe00
x-ms-ests-server: 2.1.12025.15 - WEULR2 ProdSlices
x-ms-clitelem: 1,7000218,0,,
Set-Cookie: fpc=Ah_T82wZi7hJgqcpQ9HohJiJEGHQAQAAAFaj1tgOAAAAUSo9cgEAAACyo9bYDgAAAA; expires=Sun, 17-Oct-2021 14:56:50 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; path=/; secure; httponly, stsservicecookie=estsfd; path=/; secure; samesite=none; httponly
Date: Fri, 17 Sep 2021 14:56:50 GMT
我在 MacOS 和 Linux 环境中测试了代码,两次都按预期工作。
public DeviceCodeAuthenticationLogic(PublicClientApplicationOptions msalOptions, IPublishEndpoint publishEndpoint)
{
_publishEndpoint = publishEndpoint;
_app = PublicClientApplicationBuilder.CreateWithApplicationOptions(msalOptions).Build();
var storageProperties = new StorageCreationPropertiesBuilder("user", "~/cache", msalOptions.ClientId)
.WithLinuxUnprotectedFile()
// This makes development on mac easier.
.WithMacKeyChain("app_context", "user_token")
.Build();
var cacheHelper = MsalCacheHelper.CreateAsync(storageProperties).GetAwaiter().GetResult();
cacheHelper.RegisterCache(_app.UserTokenCache);
}
public async Task<AuthenticationResult> AcquireATokenFromCacheOrDeviceCodeFlowAsync(IEnumerable<string> scopes, bool interactive = true, Action<DeviceCodeResult> deviceCodeCallback = null)
{
AuthenticationResult result = null;
var accounts = await _app.GetAccountsAsync();
if (accounts.Any())
try
{
// Attempt to get a token from the cache (or refresh it silently if needed)
result = await _app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (MsalUiRequiredException)
{
}
// No token in cache, attempt device code flow
if (result == null && interactive)
result = await GetTokenForWebApiUsingDeviceCodeFlowAsync(scopes, deviceCodeCallback);
return result;
}
private async Task<AuthenticationResult> GetTokenForWebApiUsingDeviceCodeFlowAsync(IEnumerable<string> scopes,
Action<DeviceCodeResult> deviceCodeCallback = null)
{
AuthenticationResult result;
try
{
result = await _app.AcquireTokenWithDeviceCode(scopes,
callback =>
{
if (deviceCodeCallback is not null) deviceCodeCallback(callback);
return Task.FromResult(0);
}).ExecuteAsync();
}
catch (MsalServiceException ex)
{
throw;
}
catch (OperationCanceledException)
{
result = null;
}
catch (MsalClientException ex)
{
result = null;
}
return result;
}
该错误向我表明这是我的配置错误,但它为什么会在 docker 环境之外工作。
我对此有点迷茫,非常感谢任何帮助。
【问题讨论】:
标签: c# docker asp.net-web-api msal