c# - 获取 IIS 未经授权的 html 页面而不是 web api 未经授权的响应以获取未经授权的状态
问题描述
我有一个托管在 IIS 10 (Windows Server 2016) 上的 Web API 应用程序。该应用程序有一个用于登录的 API。登录 API 装饰有实现 IAuthenticationFilter 的自定义身份验证筛选器属性。
[RoutePrefix("api/login")]
[AllowUnAuthorized]
[AuthenticationFilter]
public class LoginController : ApiController
{
[HttpPost]
public IHttpActionResult Login()
{
//Code to return token if passed authentication in the Authentication Filter
}
}
如果登录凭据(用户名和密码)无效,则身份验证过滤器属性会在上下文中设置 ErrorResult,返回状态代码 401(“未授权”)和响应消息。
public class AuthenticationFilter : Attribute, IAuthenticationFilter
{
public bool AllowMultiple => false;
public async Task AuthenticateAsync(HttpAuthenticationContext context,
CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization =
request.Headers.Authorization;
if (authorization == null)
{
return;
}
if (authorization.Scheme != "Basic")
{
return;
}
Tuple<string, string> credentials =
ExtractCredentials(request.Headers);
if (credentials == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid
credentials", request);
return;
}
string userName = credentials.Item1;
string password = credentials.Item2;
IAuthenticationService
service=container.Resolve<IAuthenticationService>();
var user = service.GetUser(userName, password);
if (user == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
return;
}
//Code to set principal if authentication passed
}
这是 AuthenticationFailureResult 类的代码。
internal class AuthenticationFailureResult : IHttpActionResult
{
public string ReasonPhrase { get; private set; }
public HttpRequestMessage Request { get; private set; }
public AuthenticationFailureResult(string reasonPhrase, HttpRequestMessage request)
{
ReasonPhrase = reasonPhrase;
Request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
private HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
response.ReasonPhrase = ReasonPhrase;
return response;
}
}
此代码运行良好,并返回 401 状态代码以及原因短语中指定的消息。但是我不知道由于什么变化,API 突然返回一个通常由 IIS 返回的 html 页面,并显示消息“401 - 未经授权:由于凭据无效而拒绝访问。” 而不是在身份验证过滤器中设置的错误响应。请注意,在 IISExpress 中运行时,相同的 API 会按预期工作
到目前为止我做了什么:
- 检查 Web.config 并验证 CustomErrors Mode 设置为“On”
- 确保在 IIS 中站点的“身份验证”部分中启用了“匿名身份验证”
在 Web.config 中添加了以下内容
<system.webServer> <modules runAllManagedModulesForAllRequests="true"/> </system.webServer>
奇怪的是,当身份验证通过时,web api 返回正确的 JSON 响应
编辑1:
这是 ChallengeAsync 方法
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
var challenge = new AuthenticationHeaderValue("Basic");
context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result);
return Task.FromResult(0);
}
AddChallengeOnUnauthorizedResult 的实现
public class AddChallengeOnUnauthorizedResult : IHttpActionResult
{
public AddChallengeOnUnauthorizedResult(AuthenticationHeaderValue challenge, IHttpActionResult innerResult)
{
Challenge = challenge;
InnerResult = innerResult;
}
public AuthenticationHeaderValue Challenge { get; private set; }
public IHttpActionResult InnerResult { get; private set; }
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = await InnerResult.ExecuteAsync(cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
// Only add one challenge per authentication scheme.
if (!response.Headers.WwwAuthenticate.Any((h) => h.Scheme == Challenge.Scheme))
{
response.Headers.WwwAuthenticate.Add(Challenge);
}
}
return response;
}
}
解决方案
解决方案是在 Web.config 中添加以下两个设置。
<system.webServer>
<httpErrors existingResponse="PassThrough" />
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
推荐阅读
- javascript - Material UI - 将图标作为道具传递
- node.js - 如何在测试模式下测试 Stripe Express 手动支付?
- java - 如何将全局变量传递给放心标头?
- javascript - for循环中的Javascript闭包-使用的变量是否计数?
- for-loop - R中for循环的问题
- ios - 如何根据表格视图单元格中的标签转到不同的视图控制器
- java - 设置约束时 Workmanager 不工作 (Android)
- python - 在 Keras 中使用 LSTM 预测股票(Python 3.7、Tensorflow 2.1.0)
- reactjs - ReferenceError:anchorEl 未定义
- javascript - gatsby/react中多维数组上的map()方法,尝试在div中包装内部循环时出错