Где найти идентификатор и секрет для OAuth2.0 и что означают «мнимые функции»? - PullRequest
1 голос
/ 16 мая 2019

Я следую этой документации , чтобы реализовать OAuth2.0 в моем приложении для флаттера, и не понимаю нескольких вещей, вот код из документации:

import 'dart:io';
import 'package:oauth2/oauth2.dart' as oauth2;

// These URLs are endpoints that are provided by the authorization
// server. They're usually included in the server's documentation of its
// OAuth2 API.
final authorizationEndpoint =
    Uri.parse("http://example.com/oauth2/authorization");
final tokenEndpoint =
    Uri.parse("http://example.com/oauth2/token");

// The authorization server will issue each client a separate client
// identifier and secret, which allows the server to tell which client
// is accessing it. Some servers may also have an anonymous
// identifier/secret pair that any client may use.
//
// Note that clients whose source code or binary executable is readily
// available may not be able to make sure the client secret is kept a
// secret. This is fine; OAuth2 servers generally won't rely on knowing
// with certainty that a client is who it claims to be.
final identifier = "my client identifier";
final secret = "my client secret";

// This is a URL on your application's server. The authorization server
// will redirect the resource owner here once they've authorized the
// client. The redirection will include the authorization code in the
// query parameters.
final redirectUrl = Uri.parse("http://my-site.com/oauth2-redirect");

/// A file in which the users credentials are stored persistently. If the server
/// issues a refresh token allowing the client to refresh outdated credentials,
/// these may be valid indefinitely, meaning the user never has to
/// re-authenticate.
final credentialsFile = new File("~/.myapp/credentials.json");

/// Either load an OAuth2 client from saved credentials or authenticate a new
/// one.
Future<oauth2.Client> getClient() async {
  var exists = await credentialsFile.exists();

  // If the OAuth2 credentials have already been saved from a previous run, we
  // just want to reload them.
  if (exists) {
    var credentials = new oauth2.Credentials.fromJson(
        await credentialsFile.readAsString());
    return new oauth2.Client(credentials,
        identifier: identifier, secret: secret);
  }

  // If we don't have OAuth2 credentials yet, we need to get the resource owner
  // to authorize us. We're assuming here that we're a command-line application.
  var grant = new oauth2.AuthorizationCodeGrant(
      identifier, authorizationEndpoint, tokenEndpoint,
      secret: secret);

  // Redirect the resource owner to the authorization URL. This will be a URL on
  // the authorization server (authorizationEndpoint with some additional query
  // parameters). Once the resource owner has authorized, they'll be redirected
  // to `redirectUrl` with an authorization code.
  //
  // `redirect` is an imaginary function that redirects the resource
  // owner's browser.
  await redirect(grant.getAuthorizationUrl(redirectUrl));

  // Another imaginary function that listens for a request to `redirectUrl`.
  var request = await listen(redirectUrl);

  // Once the user is redirected to `redirectUrl`, pass the query parameters to
  // the AuthorizationCodeGrant. It will validate them and extract the
  // authorization code to create a new Client.
  return await grant.handleAuthorizationResponse(request.uri.queryParameters);
}

main() async {
  var client = await loadClient();

  // Once you have a Client, you can use it just like any other HTTP client.
  var result = client.read("http://example.com/protected-resources.txt");

  // Once we're done with the client, save the credentials file. This ensures
  // that if the credentials were automatically refreshed while using the
  // client, the new credentials are available for the next run of the
  // program.
  await credentialsFile.writeAsString(client.credentials.toJson());

  print(result);
}

Где я могу найти идентификатор и секрет? Это показано на странице /.well-known/openid-configuration? Также, как мне реализовать эти функции:

await redirect(grant.getAuthorizationUrl(redirectUrl));
var request = await listen(redirectUrl);
var client = await loadClient();

В документации упоминается, что это мнимая функция. Как мне реализовать эти функции?

enter image description here

1 Ответ

1 голос
/ 16 мая 2019

OAuth с флаттером никогда не будет полностью прямым на Android или iOS, потому что ему не хватает глубокой интеграции с ОС, поэтому вам придется немного поконфигурировать для каждой ОС. И, честно говоря, на родном Android / iOS не все так просто.

И этот плагин, на который вы смотрите, кажется, гораздо больше ориентирован на серверное приложение, поэтому он не имеет полного смысла для трепетного разработчика. Однако его невозможно использовать!

Главное, что позволяет OAuth работать, - это использование пользовательской схемы URL или универсальной ссылки. Пользовательская схема URL - это что-то вроде com.myapp.customurlscheme: // - она ​​используется вместо «https». Универсальная ссылка использует https и веб-сайт, т. Е. https://myapp.com/customurl/.. Важным отличием является то, что для использования универсальной ссылки вы должны контролировать веб-сайт и загрузить файл, который Apple может проверить, чтобы убедиться, что вы дали разрешение на замену приложения. этот сайт или эта часть сайта. Если у пользователя установлено приложение, ему будет показано его при переходе по этому URL; если они этого не сделают, им что-то покажет веб-сайт (обычно ссылка для установки приложения).

В случае, когда вы являетесь клиентом для аутентификации с OAuth, вы обычно не хотите реплицировать часть веб-сайта, поскольку все, что вы делаете, - это создание URL-адреса обратного вызова (перенаправления), так что вы, вероятно, будете используя собственную схему URL. Это должно быть сделано путем добавления в ваши файлы AndroidManifest.xml или Info.plist.

Для Info.plist для iOS, который выглядит примерно так:

  <key>CFBundleURLTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeRole</key>
      <string>Editor</string>
      <key>CFBundleURLName</key>
      <string>[ANY_URL_NAME]</string>
      <key>CFBundleURLSchemes</key>
      <array>
        <string>[YOUR_SCHEME]</string>
      </array>
    </dict>
  </array>

А для AndroidManifest.xml что-то вроде:

    <activity>

      ...

      <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:scheme="[YOUR_SCHEME]"
          android:host="[YOUR_HOST]" />
      </intent-filter>

После того, как вы это настроите, вы можете добавить слушателей, когда приложение «открывается» с одним из этих пользовательских URL. Это немного болезненно, но, к счастью, кто-то создал плагин, который помогает: Универсальные ссылки (и благодарю их за пример конфигурации выше, так как я бесстыдно украл его из их документации). Вы можете использовать его метод getInitialLink() в своей основной функции (или где-то в этом роде) и / или получить поток ссылок для прослушивания для использования getLinksStream(). Я думаю, что второй вы будете использовать, так как приложение уже открыто, когда вы запускаете рабочий процесс OAuth / OpenID - так что вы начнете слушать либо сразу после открытия приложения, либо прямо перед тем, как начать с OAuth. звоните.

Хорошо, это было много. Однако для этого есть причина - то, что это сделало, позволило вашему приложению получать перенаправления из браузера или другого приложения. Таким образом, если вы обрабатываете getLinksStream, вы можете более или менее получить обратный вызов с сервера oauth2. Вы можете настроить систему, в которой вы создадите будущее, которое ожидает, когда определенная ссылка будет передана через поток ссылок.

Так что охватывает

// Another imaginary function that listens for a request to 'redirectUrl'.

var request = await listen(redirectUrl);

Теперь нам нужно что-то сделать с этим первым imaginary function. Оказывается, в случае приложения это вовсе не воображаемо - вам нужно запустить этот URL, а не перенаправлять страницу, как на сервере. Для этого есть плагин: Url Launcher

Так что там, где говорится, await redirect(grant.getAuthorizationUrl(redirectUrl));, то, что вы на самом деле хотите сделать, это запустить grant.getAuthorizationUrl с launch() url_launcher (с соответствующими флагами, которые вам придется выяснить с помощью тестирования. Возможно, вы захотите принудительно использовать браузер или нет, в зависимости от того, есть ли на сервере OAuth приложение, которое может обработать для него аутентификацию. Если они это сделают, вы, вероятно, захотите, чтобы URL-адрес открывался в их приложении, чтобы пользователь уже вошел в систему).

В эту головоломку нужно добавить еще пару кусочков. Первый - это redirectUrl, который вы должны передать в getAuthorizationUrl. Что я там положу, спросите вы ?! Ну, вы используете ту изящную пользовательскую схему приложения, которую мы создали ранее! Таким образом, URL перенаправления будет выглядеть примерно так: com.myapp.customurlscheme: // customurlredirect.

Итак, рабочий процесс подготовки токенов OAuth выглядит примерно так:

  • вы запускаете auth url для сервера
  • пользователю показывается страница входа в систему или страница разрешений, или что бы сервер ни делал
  • после того, как пользователь утвердил запрос, сервер перенаправляет пользователя обратно в ваше приложение (оно может спросить его«Хотите открыть?» Или что-то в этом роде.
  • Ваше приложение получает обратный вызов с кодом авторизации
  • Ваше приложение должно запрашивать токены, используя этот код авторизации (я полагаю, что это обрабатываетсяhandleAuthorizationResponse).

Теперь, прежде чем реализовать все это, нужно подумать о нескольких вещах.

  1. Если бы это было серверное приложение, у вас мог бы быть секретный секрет, который доказывает серверу OAuth, что ваше приложение является клиентом, которым он себя считает.Вы получите это с сервера OAuth и предоставите его непосредственно серверу.Однако, поскольку вы пишете приложение, нет (простого) способа обеспечить этот секретный секрет.Поэтому вместо использования обычного OAuth вы должны использовать поток кода авторизации OAuth с PKCE, а не client_secret.Если вам это не по душе, вам следует почитать PKCE - Auth0 имеет хорошую запись .Сервер OAuth, с которым вы работаете, также должен это поддерживать, но если вы сделаете это без него, ваш процесс входа будет небезопасным.

  2. Сервер OAuth, с которым вы общаетесь, долженоба понимают и принимают собственные схемы URL.Большинство крупных из них делают, и у них есть документация, похожая на эту, которая должна провести вас через тот же процесс (но не специфично для флаттера).И фактически они фактически определяют, какими должны быть пользовательские схемы URL - в случае Facebook, если идентификатор вашего приложения равен 1234567, тогда настраиваемая схема URL будет выглядеть примерно так: fb1234567://.

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

Это было много информации, но, к сожалению, OAuth2 не так уж прост (и реально, это не может быть намного проще, если он делает то, что ему нужно).Удачи в вашем приложении!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...