.Net Core Facebook OAuth вызывает ошибку "redirect_uri_mismatch"
Всем привет, использую проект на Razor Page, на сервере сайт работает через Reverse Proxy с помощью Apache2. Когда запускаю сайт на localhost проблема не появляется, авторизация проходит отлично. В запросе с локального хоста передается redirect_url в запросе: https://localhost:5081/signin-facebook но с хостинга, передается вот такой redirect_url: http://mysite.ru/signin-facebook т.е http схема вместо https. В учетке разраба фейсбука, нельзя указывать http протоколы в принимаемых redirect_url, принимаются только https. При попытке авторизации с хостинга, выдает ошибку ниже:
info: AspNet.Security.OAuth.Facebook.FacebookAuthenticationHandler[12]
AuthenticationScheme: Facebook was challenged.
info: AspNet.Security.OAuth.Facebook.FacebookAuthenticationHandler[4]
Error from RemoteAuthentication: OAuth token endpoint failure: Status: BadRequest;Headers: Vary: Accept-Encoding
WWW-Authenticate: OAuth "Facebook Platform" "redirect_uri_mismatch"
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context,
Task task)
Хостинг работает через CDN Cloudflare, если это важно. Виртуал хост апача выглядит вот так:
<VirtualHost *:80>
ProxyPreserveHost On
ProxyPass / http://localhost:5080/
ProxyPassReverse / http://localhost:5080/
ServerName mysite.ru
</VirtualHost>
<VirtualHost *:443>
ServerName mysite.ru
ProxyPass / http://localhost:5081/
ProxyPassReverse / http://localhost:5081/
<IfModule mod_headers.c>
Header always add Strict-Transport-Security "max-age=15768000"
RequestHeader unset Proxy early
Header set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header set X-XSS-Protection "1; mode=block"
</IfModule>
</VirtualHost>
При запуске сайта, выводятся логи:
info: Microsoft.Hosting.Lifetime[0] [102/102]
Now listening on: http://localhost:5080
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5081
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
Как разрешить ошибку, куда копать? В сторону библиотеки OAuth (Microsoft.AspNetCore.Authentication.OAuth) или в сторону хостинга (апач, реверс прокси и т.п).
Дополнено: Если добавить в Startup.cs код:
app.Use((context, next) =>
{
if (context.Request.Headers["x-forwarded-proto"] == "https")
{
context.Request.Scheme = "https";
}
return next();
});
То в запрос к фейсбуку redirect_url меняет схему на https, но мой сайт выдает ошибку 500 при возврате на адрес https://mystite.ru/signin-facebook?code=returnedCodeFromFacebook&state=someState
Ответы (1 шт):
Методом проб и ошибок, найдено РЕШЕНИЕ
После редактирования apache2 виртуал хоста на то что ниже, OAuth аутентификация стала проходить как следует.
<VirtualHost *:80>
ProxyPass / http://localhost:5080/
ProxyPassReverse / http://localhost:5080/
ServerName mysite.ru
</VirtualHost>
<VirtualHost *:443>
ProxyPreserveHost On
ServerName mysite.ru
SSLProxyEngine on
SSLProxyCheckPeerCN off
ProxyPass / https://localhost:5081/
ProxyPassReverse / https://localhost:5081/
</VirtualHost>
Для того что бы всё заработало, мне пришлось отключить проксирование через сервера cloudflare, иначе почему то с фейсбука редайректило на localhost:5081 вместо доменного имени (игнорировалась директива апача ProxyPreserveHost), кто знает как подружиться в этом плане с cloudflare, расскажите, буду благодарен.
Так же пришлось включить SSLProxyEngine и создать сертификаты (т.к вероятно клоудфлейровские без проксирования не используются), у меня почему то выбивало ошибку рукопожатия с моими созданными сертификатами, по этому в апач добавил директиву SSLProxyCheckPeerCN
Это минимальный набор виртуального хоста в моем случае, для того что бы всё работало (в пример виртуал хоста не стал вписывать ссылки на сертификаты, но они там должны быть).
Интеграция с Cloudflare CDN
Для того, что бы проксирование заработало через cloudflare, нужно слегка подредактировать Virtual Host apache2 и загрузить на хостинг (где сайт расположен) CA сертификат cloudflare (который можно получить в настройках клоудфлейра), так же нужно в виртуал хосте убрать блок с 80 портом и оставить только 443 (SSL) иначе будет ошибка 500, итоговый виртуал хост выглядит вот так:
<VirtualHost *:443>
ProxyPreserveHost On
ServerName mysite.ru
SSLProxyEngine on
SSLProxyCheckPeerCN off
ProxyPass / https://localhost:5081/
ProxyPassReverse / https://localhost:5081/
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4
SSLCertificateFile /etc/letsencrypt/live/mysite.ru/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mysite.ru/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/mysite.ru/chain.pem
SSLCACertificateFile /etc/letsencrypt/live/mysite.ru/origin-pull-ca.pem
SSLHonorCipherOrder On
SSLUseStapling On
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors Off
SSLVerifyDepth 1
<IfModule mod_headers.c>
Header always add Strict-Transport-Security "max-age=15768000"
Header set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header set X-XSS-Protection "1; mode=block"
</IfModule>
ErrorLog /var/log/apache2/mysite-error.log
CustomLog /var/log/apache2/mysite-access.log common
</VirtualHost>
От использования некоторых заголовков в виртуал хосте думаю можно отказаться, заменив аналогами из кода самого сайта .net core (Razor в моем случае) но я для "уверенности" бахнул и в виртуал хост.
В панели Cloudflare можно включать теперь SSL/TLS Mode в режим Full или Full(Strict) всё будет прекрасно работать, так же можно накрутить всякие другие "улучшайки" у CDN, всё будет работать, включая выданный самим клоудфлейром сертификат на основной домен и все поддомены.