- Я создал веб-API .NET Core 2.1 с анонимным доступом с помощью Visual Studio 2017.
- Я успешно внедрил защиту идентификаторов приложений Azure AD в своем API,
используя этот и этот учебник.
- Как и ожидалось, я больше не могу получить доступ к API анонимно. Но я могу
успешно вызвать его, указав соответствующее значение токена доступа.
- Затем я попытался отменить безопасность, которую я установил в API
проект. Я закомментировал весь соответствующий код, ожидая, что я
будет снова иметь возможность получить доступ к API анонимно.
Но вместо этого я получаю следующее исключение. Я неоднократно воспроизводил эту проблему (запускать проекты локально). Как только я впервые «аутентифицируюсь» по API, я больше не могу отменить эти изменения и сделать их доступными анонимно.
Это задумано?
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS90002: Tenant authorize not found. This may happen if there are no active subscriptions for the tenant. Check with your subscription administrator.
Trace ID: b9285104-e24c-43cc-b3fa-6f843eef5a00
Correlation ID: e1d4a740-ccab-4ea4-9fb0-b12608d116ca
Timestamp: 2018-11-02 15:18:19Z ---> System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (BadRequest). ---> Microsoft.IdentityModel.Clients.ActiveDirectory.AdalException: {"error":"invalid_request","error_description":"AADSTS90002: Tenant authorize not found. This may happen if there are no active subscriptions for the tenant. Check with your subscription administrator.\r\nTrace ID: b9285104-e24c-43cc-b3fa-6f843eef5a00\r\nCorrelation ID: e1d4a740-ccab-4ea4-9fb0-b12608d116ca\r\nTimestamp: 2018-11-02 15:18:19Z","error_codes":[90002],"timestamp":"2018-11-02 15:18:19Z","trace_id":"b9285104-e24c-43cc-b3fa-6f843eef5a00","correlation_id":"e1d4a740-ccab-4ea4-9fb0-b12608d116ca"}: Unknown error
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Http.AdalHttpClient.GetResponseAsync[T](Boolean respondToDeviceAuthChallenge)
at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Http.AdalHttpClient.GetResponseAsync[T]()
at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.AcquireTokenHandlerBase.SendHttpMessageAsync(IRequestParameters requestParameters)
at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.AcquireTokenHandlerBase.SendTokenRequestAsync()
at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.AcquireTokenHandlerBase.CheckAndAcquireTokenUsingBrokerAsync()
at Microsoft.IdentityModel.Clients.ActiveDirectory.Internal.Flows.AcquireTokenHandlerBase.RunAsync()
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireTokenForClientCommonAsync(String resource, ClientKey clientKey)
at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireTokenAsync(String resource, IClientAssertionCertificate clientCertificate)
at APIProject.Controllers.ExclusionRequestsController.Get() in C:\Users\Tracy\source\repos\APIProject\Controllers\ExclusionRequestsController.cs:line 61
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at System.Threading.Tasks.ValueTask`1.get_Result()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at NSwag.AspNetCore.Middlewares.SwaggerUiIndexMiddleware`1.Invoke(HttpContext context)
at NSwag.AspNetCore.Middlewares.RedirectMiddleware.Invoke(HttpContext context)
at NSwag.AspNetCore.Middlewares.AspNetCoreToSwaggerMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
ErrorCode: invalid_request
StatusCode: 400
По-видимому, он все еще пытается аутентифицировать запрос, но я не уверен, почему, потому что весь соответствующий код аутентификации был удален.
Мое лучшее предположение - что-то меняется в Visual Studio и никогда не меняется обратно. Но я подтвердил, что ничего не меняется в файлах проекта VS после этой первой аутентификации.
Для справки, вот код в Startup.cs, который я использую для защиты API:
namespace APIProject
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public static IConfiguration AppSetting { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
p => p.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
});
services.AddSwagger();
//Authentication
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // sets both authenticate and challenge default schemes
.AddJwtBearer(options =>
{
options.Audience = Configuration["AppSettings:Audience"];
options.Authority = "https://sts.windows.net/[TenantID]";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseCors("AllowAll");
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
// Register the Swagger generator and the Swagger UI middlewares
app.UseSwaggerUi3WithApiExplorer(settings =>
{
settings.GeneratorSettings.DefaultPropertyNameHandling =
PropertyNameHandling.CamelCase;
});
app.UseAuthentication();
app.UseMvc();
}
}
static class ConfigurationManager
{
public static IConfiguration AppSetting { get; }
static ConfigurationManager()
{
AppSetting = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("AppSettings.json")
.Build();
}
}
}
А вот код, который я использую для аутентификации по API:
public async Task<JsonResult> OnGetSummaryView()
{
try
{
HttpClient httpClient = new HttpClient();
AuthenticationContext authContext =
new AuthenticationContext("https://login.microsoftonline.com/[Tenant ID]");
ClientCredential clientCredential =
new ClientCredential("[App ID]", "[App Secret]");
AuthenticationResult result =
await authContext.AcquireTokenAsync("[App URI]", clientCredential);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string requestUrl = $"https://localhost:44338/api/ExclusionRequests/GetSummaryView";
HttpRequestMessage message = new HttpRequestMessage(new HttpMethod("POST"), requestUrl);
message.Content = new StringContent("{}", Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.SendAsync(message);
dynamic jsonContent = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
return new JsonResult(jsonContent);
}
}
catch (Exception e)
{
//Add exception handling here.
return null;
}
}