У меня есть Identity Server (использующий IdentityServer4), веб-API, который использует Identity Server для авторизации, и приложение Xamarin, которое использует Identity Server для входа в систему и аутентификации API.
Когда я запускаю все три части локально из Visual Studio, я могу войти в систему с помощью приложения Xamarin, получить токен и использовать этот токен для выполнения вызовов API. Однако, когда я публикую Identity Server на веб-сервере (в той же сети), он завершается неудачно в тот момент, когда он пытается получить токен. Таким образом, он показывает страницу входа в систему, кажется, что он принимает имя входа, но POST для получения токена завершается ошибкой с 401 несанкционированной ошибкой в ответе.
Я также настроил Identity Server, чтобы разрешить Swagger подключаться для тестирования API, и это позволяет мне входить в систему (используя Implicit), используя Identity Server, установленный на веб-сервере.
Это метод, который выполняет POST в приложении Xamarin (в основном, скопировано из примера eShopOnContainers):
public async Task<TResult> PostAsync<TResult>(string uri, string data, string clientId, string clientSecret)
{
HttpClient httpClient = CreateHttpClient(string.Empty);
if (!string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret))
{
AddBasicAuthenticationHeader(httpClient, clientId, clientSecret);
}
var content = new StringContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
await HandleResponse(response);
string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() =>
JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
return result;
}
Вот метод вызова для получения токена:
public async Task<UserToken> GetTokenAsync(string code)
{
string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}&code_verifier={2}",
code, WebUtility.UrlEncode(Settings.Service.IdentityCallback), _codeVerifier);
var token = await _requestProvider.PostAsync<UserToken>(
Settings.Service.IdentityTokenEndpoint, data, Settings.Service.IdentityClientId, Settings.Service.IdentityClientSecret);
return token;
}
URI - "http://myserver:5002/connect/token"
, а заголовки:
Accept: "application/json"
Authorization: "Basic SW5zdGVtLkFDSVMuTW9iaWxlOnNlY3JldA=="
ContentType: "application/x-www-form-urlencoded"
Журнал на веб-сервере дает мне это:
info: IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator[0]
Showing login: User is not authenticated
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3.4723ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3D0dc5d79410db46739c798ce004ac89b8%26code_challenge%3DAuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c%26code_challenge_method%3DS256%26state%3D031db7b77c7249aebb6f7ae205dac016
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Login", controller = "Account"}. Executing action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) with arguments (/connect/authorize/callback?client_id=Company.App.Mobile&client_secret=secret&response_type=code%20id_token&scope=openid%20profile%20app_api%20offline_access&redirect_uri=http%3A%2F%2Fmyserver%3A5002%2FAccount%2FRedirect&nonce=0dc5d79410db46739c798ce004ac89b8&code_challenge=AuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c&code_challenge_method=S256&state=031db7b77c7249aebb6f7ae205dac016) - Validation state: Valid
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer), returned result Microsoft.AspNetCore.Mvc.ViewResult in 0.3611ms.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]
Executing ViewResult, running view Login.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4]
Executed ViewResult - view Login executed in 1.7974ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) in 2.4715ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3.1044ms 200 text/html; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/css/site.css
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /css/site.css was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.6236ms 304 text/css
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/lib/bootstrap/js/bootstrap.js
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /lib/bootstrap/js/bootstrap.js was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.3461ms 304 application/javascript
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/lib/jquery/jquery.js
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /lib/jquery/jquery.js was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2798ms 304 application/javascript
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/icon.png
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /icon.png was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2655ms 304 image/png
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/lib/bootstrap/css/bootstrap.css
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /lib/bootstrap/css/bootstrap.css was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.26ms 304 text/css
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 POST http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3D0dc5d79410db46739c798ce004ac89b8%26code_challenge%3DAuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c%26code_challenge_method%3DS256%26state%3D031db7b77c7249aebb6f7ae205dac016 application/x-www-form-urlencoded 712
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Login", controller = "Account"}. Executing action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) with arguments (IdentityServer4.Quickstart.UI.LoginInputModel, login) - Validation state: Valid
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: idsrv signed in.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer), returned result Microsoft.AspNetCore.Mvc.ViewResult in 1.0902ms.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]
Executing ViewResult, running view Redirect.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4]
Executed ViewResult - view Redirect executed in 10.0474ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) in 12.3805ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 13.1928ms 302 text/html; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/connect/authorize/callback?client_id=Company.App.Mobile&client_secret=secret&response_type=code%20id_token&scope=openid%20profile%20app_api%20offline_access&redirect_uri=http%3A%2F%2Fmyserver%3A5002%2FAccount%2FRedirect&nonce=0dc5d79410db46739c798ce004ac89b8&code_challenge=AuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c&code_challenge_method=S256&state=031db7b77c7249aebb6f7ae205dac016
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint for /connect/authorize/callback
info: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint[0]
ValidatedAuthorizeRequest
{
"ClientId": "Company.App.Mobile",
"ClientName": "App Mobile",
"RedirectUri": "http://myserver:5002/Account/Redirect",
"AllowedRedirectUris": [
"http://myserver:5002/Account/Redirect"
],
"SubjectId": "eb194e4a-a2f7-482c-8c43-204567ebd591",
"ResponseType": "code id_token",
"ResponseMode": "fragment",
"GrantType": "hybrid",
"RequestedScopes": "openid profile app_api offline_access",
"State": "031db7b77c7249aebb6f7ae205dac016",
"Nonce": "0dc5d79410db46739c798ce004ac89b8",
"SessionId": "0ed1a950919c3b368e1249ec74e35f2c",
"Raw": {
"client_id": "Company.App.Mobile",
"client_secret": "secret",
"response_type": "code id_token",
"scope": "openid profile app_api offline_access",
"redirect_uri": "http://myserver:5002/Account/Redirect",
"nonce": "0dc5d79410db46739c798ce004ac89b8",
"code_challenge": "AuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c",
"code_challenge_method": "S256",
"state": "031db7b77c7249aebb6f7ae205dac016"
}
}
info: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint[0]
Authorize endpoint response
{
"SubjectId": "eb194e4a-a2f7-482c-8c43-204567ebd591",
"ClientId": "Company.App.Mobile",
"RedirectUri": "http://myserver:5002/Account/Redirect",
"State": "031db7b77c7249aebb6f7ae205dac016",
"Scope": "openid profile app_api offline_access"
}
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: idsrv signed in.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 40.3114ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/Account/Redirect
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.9519ms 404
Адрес "http://myserver:5002/Account/Redirect"
на самом деле не существует, потому что клиент является приложением Xamarin, поэтому я не думаю, что 404 в конце - это проблема. Похоже, в журнале нет ничего для вызова токена.
Вот клиентская конфигурация для Identity Server:
new Client
{
ClientName = "ACIS Mobile",
ClientId = "Instem.ACIS.Mobile",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = {$"{identityUri}/Account/Redirect"},
RequireConsent = false,
RequirePkce = true,
PostLogoutRedirectUris = {$"{identityUri}/Account/Redirecting"},
AllowedCorsOrigins = { "http://xamarinapp" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.OfflineAccess,
"acis_api"
},
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true
},
new Client
{
ClientName = "Swagger UI",
ClientId="swaggerui",
AllowedGrantTypes=GrantTypes.Implicit,
AllowAccessTokensViaBrowser=true,
RedirectUris = { $"{webApiUri}/oauth2-redirect.html" },
PostLogoutRedirectUris={ $"{webApiUri}/" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"acis_api"
}
}
Настройка запуска сервера идентификации довольно проста:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddIdentityServer()
.AddInMemoryClients(Config.GetClients(Configuration))
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddTestUsers(Config.GetUsers())
//.AddDeveloperSigningCredential();
.AddSigningCredential("some certificate thumbprint", System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, NameType.Thumbprint);
services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
options.ClientId = "someclientid";
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientSecret = "somesecret";
});
}
// 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.UseIdentityServer();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
В IIS я настроил его на анонимную и базовую аутентификацию.
Это в значительной степени новое для меня, и я добивался прогресса до этого момента, но я не вижу никакой причины, по которой он дает мне 401 Несанкционированную ошибку, и я даже не вижу ничего в каких-либо журналах, чтобы дать мне на что угодно.
Edit:
Я нашел файл журнала с дополнительной информацией:
2019-01-08 12:08:51 172.26.2.174 POST /Account/Login ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 5002 - 172.16.190.147 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+WebView/3.0)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 302 0 0 156
2019-01-08 12:09:49 172.26.2.174 GET /connect/authorize/callback client_id=Company.App.Mobile&client_secret=secret&response_type=code%20id_token&scope=openid%20profile%20app_api%20offline_access&redirect_uri=http%3A%2F%2Fmyserver%3A5002%2FAccount%2FRedirect&nonce=dc06cb800d6f4f729df03a986ff2f165&code_challenge=N343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo&code_challenge_method=S256&state=86f26cf6a5184d9a8263aac954711819 5002 - 172.16.190.147 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+WebView/3.0)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 302 0 0 593
2019-01-08 12:10:33 172.26.2.174 POST /connect/token - 5002 Company.App.Mobile 172.16.190.147 - - 401 1 1326 50
2019-01-08 12:10:33 172.26.2.174 GET /Account/Redirect - 5002 - 172.16.190.147 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+WebView/3.0)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 404 0 0 15
Это линия соединения / токена с ошибкой 401.