這幾天再用Insomnia測試API時,發現到:
使用IIS Express啟動網頁時,API可以透過Insomnia成功呼叫。
但使用Kestrel(https)啟動網頁時,呼叫API會一直回應401 Unauthorized的錯誤,但直接用瀏覽器卻又可以成功呼叫API。
在看這篇文章前,建議先去看一下這篇.Net Core 登入驗證方式
先對Windows驗證. Kerberos(Negotiate)以及 TNLM有點概念後,再回來這裡。
可能比較不會看的霧沙沙@@
launchSettings.json設定:
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56467",
"sslPort": 44371
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
//"launchUrl": "dar",
"applicationUrl": "http://localhost:5153",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
//"launchUrl": "dar",
"applicationUrl": "https://localhost:7162;http://localhost:5153",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
//"launchUrl": "dar",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
launchSettings.json的CommandName如果不是使用IIS Express的話,預設就會使用Kestrel來當作網頁伺服器來啟動網頁。
Kerstrel啟動:
profiles底下的http & https
IIS啟動:
profiles底下的IIS Express,iisSettings可以進行參數設定
Insomnia無法成功呼叫API錯誤重新呈現 & 問題發生原因:
由於開發API時,我是選用https(Port:7162)
來啟動我的網頁。先前提到launchSettings.json的CommandName如果不是使用IIS Express的話,預設就會使用Kestrel來當作網頁伺服器來啟動網頁,當使用Kestrel + NTLM呼叫API時就會回應401錯誤。


但直接用網頁呼叫API又沒有問題(請忽略bad request,畢竟只是個測試API,至少是確定能確實呼叫API。)

一直找不到錯誤發生的原因,後來看到StackOverflow上也有人有提出Postman也有類似的問題[.NET Core 3.1 WebApi project + NTLM Authentication]。只知道使用API測試軟體時,如果使用Kestrel + NTLM,好像就會出現401 Unauthorized的問題。這篇文章[Postman 401 Unauthorized using NTLM]另外提到,這問題應該是跟NTLM的版本有關。Postman只支援發送NTLMv1。但我覺得[Windows Authentication not working in Kestrel running in Linux (Ubuntu)]] 裡面的這個回覆才是正解。






簡單的做個總結就是,NTLM不支援HTTP/2。但Insomnia發出Request給Kestrel時,預設使用的HTTP版本為HTTP/2,Kestrel也用HTTP/2回應的話,因為無法進行NTLM驗證,導致401錯誤。但Insomnia發出Request給IIS Express時,IIS Express會自己選擇以HTTP/1回應,再重新進行以HTTP/1進行TLS交握流程,NTLM支援HTTP/1,所以不會有問題。
解決方法1_改用IIS_Express啟動網頁:
於是我們改用IIS Express(Port:44371)
來啟動網頁

卻還是出現了錯誤

原來是我們有啟用了Windows驗證,launchSettings.json裡面的windowsAuthentication也要從false改成true。


再透過IIS Express重新啟動一次網頁,輸入NTML驗證帳號密碼後,再重新呼叫一次API,可以看到API呼叫成功了(請忽略測試的Bad Request結果)!!

解決方法2_Kestrel的驗證方式由NTLM改成用JWT來進行身分驗證
另外一個專案的launchSettings.json如下:
{
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:9881",
"sslPort": 44313
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

順便補上用Postman的測試結果,Kestrel + NTLM回應401。


順便補上用Postman的測試結果,Kestrel + JWT回應200。

總結一下:
當使用API測試軟體時(這篇文章主要以Insomnia為主):
Kestrel + NTLM => 401
Kestrel + JWT => 200
IIS Express + NTLM => 200
手動修改Insomnia HTTP版本測試:
今天發現Insomnia可以設定發出Request要使用的HTTP Protocol,照之前的測試來看,Kestrel + NTLM會回應401的原因是因為HTTP/2不支援Windows驗證的問題。那我如果手動把Insomnia發出Request時的HTTP Protocol改成HTTP/1,再去呼叫Kestrel+NTLM的API會不會就能呼叫成功呢?

但結果還是出現了401。事到如今,我也想不出真正原因是什麼了…

Ref:
1.在 ASP.NET Core 中設定 Windows 驗證
2.Postman 401 Unauthorized using NTLM
3.冷知識 - NTLMv1 為什麼不安全?
4.Windows Authentication not working in Kestrel running in Linux (Ubuntu)
5.什麼是 HTTP?為什麼 HTTP/2 比 HTTP/1.1 更快?
6.IIS 上的 HTTP/2
7.HTTPClient getting two 401s before success (sending wrong token)