Xamarin: перенаправление из браузера в собственное приложение не работает - PullRequest
1 голос
/ 04 июня 2019

Я следовал этой документации для реализации потока кода авторизации oauth2 в моем приложении xamarin: https://docs.microsoft.com/de-de/xamarin/xamarin-forms/data-cloud/authentication/oauth

Кроме того, я обратился к этому учебному пособию, чтобы заставить его работать с IdentityServer4 (я скопировал расширение класса OAuth2Authenticator): https://sinclairinat0r.com/2018/12/09/secure-data-access-with-identityserver4-and-xamarin-forms

Когда я запускаю поток входа, приложение перенаправляет в браузер, и я могу войти в систему и разрешить доступ к данным пользователя. К сожалению, браузер (или, я полагаю, операционная система) не перенаправляет на мое приложение. Я предполагаю, что что-то не так с моим URL-адресом перенаправления, но я не уверен. Будем благодарны за любые указания относительно того, почему это не работает.

Redirect Uri состоит из точного имени пакета в manifest.xml плюс «: / oauth2redirect». Хотя, вероятно, очевидно, я хочу упомянуть, что я заменил реальный URL нашего сервера идентификации на ipadress.

private async void StartOAuth()
        {

            var authenticator = new OAuth2AuthenticatorEx("xamarin", string.Empty, "openid profile",
                new Uri("https://ipadress:5001/connect/authorize"), new Uri("com.companyname.SApp:/oauth2redirect"), new Uri("https://ipadress:5001/connect/token"), null, true);


            authenticator.Completed += OnAuthCompleted;
            authenticator.Error += OnAuthError;

            AuthenticationState.Authenticator = authenticator;

            var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
            Debug.WriteLine("after presenter");
            presenter.Login(authenticator);

            Debug.WriteLine($"Button StartOAuth clicked!");
        }

Это соответствующий клиент сервера идентификации

private static Client XamarinClient() => new Client
        {
            ClientId = "xamarin",
            ClientName = "Xamarin",

            AllowedGrantTypes = GrantTypes.Code,
            AllowAccessTokensViaBrowser = true,
            AlwaysIncludeUserClaimsInIdToken = true,

            RequireClientSecret = false,

            RequirePkce = true,

            AccessTokenType = AccessTokenType.Jwt,
            AccessTokenLifetime = 60,

            // Custom URL for native Apps. The URL below corresponds to bundle identifier 
            // on iOS and package name on Android 
            RedirectUris =
            {
                "com.companyname.SApp:/oauth2redirect",
            },

            AllowedScopes =
            { "openid", "profile" },
        };

Забыл опубликовать мой CustomUrlSchemeInterceptorActivity:

using System;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using SApp.Services;

namespace OAuthNativeFlow.Droid
{
    [Activity(Label = "CustomUrlSchemeInterceptorActivity", NoHistory = true, LaunchMode = LaunchMode.SingleTop)]
    [IntentFilter(
        new[] { Intent.ActionView },
        Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
        DataSchemes = new[] { "com.companyname.SApp" },
        DataPath = "/oauth2redirect")]
    public class CustomUrlSchemeInterceptorActivity : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Convert Android.Net.Url to Uri
            var uri = new Uri(Intent.Data.ToString());

            // Load redirectUrl page
            AuthenticationState.Authenticator.OnPageLoading(uri);

            Finish();
        }
    }
}

Редактировать: я изменил Uris на http и использовал whireshark, чтобы поймать ответ сервера, который должен вызвать перенаправление в приложение. Это выглядит хорошо для меня, но, возможно, это помогает:

Frame 5009: 541 bytes on wire (4328 bits), 541 bytes captured (4328 bits) on interface 0
Ethernet II, Src: IntelCor_df:44:bd (28:16:ad:df:44:bd), Dst: Cisco_9f:f0:15 (00:00:0c:9f:f0:15)
Internet Protocol Version 4, Src: x.x.x.x, Dst: x.x.x.x
Transmission Control Protocol, Src Port: 5000, Dst Port: 38378, Seq: 9204, Ack: 4575, Len: 487
Hypertext Transfer Protocol
    HTTP/1.1 302 Found\r\n
        [Expert Info (Chat/Sequence): HTTP/1.1 302 Found\r\n]
        Response Version: HTTP/1.1
        Status Code: 302
        [Status Code Description: Found]
        Response Phrase: Found
    Date: Wed, 05 Jun 2019 07:55:06 GMT\r\n
    Server: Kestrel\r\n
    Content-Length: 0\r\n
        [Content length: 0]
     [truncated]Location: http://ipaddress:5000/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Dxamarin%26redirect_uri%3Dcom.companyname.SApp%253A%252Foauth2redirect%26scope%3Dopenid%2520profile%26response_type%3Dcode
    \r\n
    [HTTP response 4/5]
    [Time since request: 0.079050000 seconds]
    [Prev request in frame: 4993]
    [Prev response in frame: 5002]
    [Request in frame: 5007]
    [Next request in frame: 5010]
    [Next response in frame: 5015]
    [Request URI [truncated]: http://ipaddress:5000/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Dxamarin%26redirect_uri%3Dcom.companyname.SApp%253A%252Foauth2redirect%26scope%3Dopenid%2520profile%26response_type%3Dc]


Обновление 1: Хорошо, после нескольких попыток и разговора с коллегой, я думаю, что, по крайней мере, решил, что идентификационный сервер не является частью проблемы. Также я должен использовать https и упомянутое расширение класса OAuth2Authenticator, в противном случае я не дохожу до того, что браузер должен перенаправить в приложение. Когда я дохожу до того, что браузер показывает мне «вы будете перенаправлены», ничего не происходит. Если я вручную закрываю вкладку, моя точка останова в OnAuthCompleted срабатывает, но EventArgs в основном пусты (account имеет значение null, а IsAuthenticated имеет значение false). Точка останова в моем CustomUrlInterceptor никогда не срабатывает, что, вероятно, означает, что проблема заключается либо в моей реализации намерения для перенаправления, либо в самом redirect-uri. К сожалению, у меня нет идей. Я даже попытался вручную добавить следующее в файл Manifest.xml, взятый из github Xamarin.Auth:

<activity android:label="ActivityCustomUrlSchemeInterceptor"
    android:launchMode="singleTop" android:noHistory="true" android:name="md52ecc484fd43c6baf7f3301c3ba1d0d0c.ActivityCustomUrlSchemeInterceptor">
    <intent-filter>
      <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="android.intent.category.BROWSABLE" />
      <data android:path="/oauth2redirect" />
      <data android:scheme="com.companyname.SApp" />
    </intent-filter>
  </activity>

Может быть проблема в самоподписанном сертификате? Поскольку в настоящее время конфигурация сервера удостоверений меняется очень часто, мы еще не развернули его в Azure. Сегодня я начал запускать сервер локально на своем ноутбуке и подключаться через локальную сеть с планшета с помощью приложения.

Обновление 2: мы развернули наш identityserver4 в Azure, и, к сожалению, мало что изменилось. По какой-то причине мой CustomUrlInterceptor все еще не вызывается. Однако я нашел способ вручную запустить его через ADB с помощью

adb shell am start -a android.intent.action.VIEW -d "com.companyname.SApp:/oauth2redirect" com.companyname.SApp

Как только я это сделаю, я получу Xamarin.Auth.AuthException: Error authenticating: invalid_grant Я все еще выясняю причину, по которой я внезапно получаю invalid_grant, но основная проблема браузера, не возвращающего контроль над приложением, все еще остается.

Другое поведение, которое меня смущает, - это когда я выполняю приведенную выше команду adb, когда приложение закрыто, оно запускает приложение и сразу же показывает мне экран, на котором приложение перестало работать. Когда я выполняю команду после того, как я получаю экран перенаправления браузера (в основном, принудительно перенаправляя, когда это должно произойти), я достигаю своей точки останова в CustomUrlInterceptor, затем я получаю метод OnAuthError, и после этого приложение закрывает / вылетает. Я понимаю, почему он падает в первом случае, но не во втором.

...