Skip to content

Commit

Permalink
Merge pull request #28 from tinkoff-mobile-tech/MC-9622
Browse files Browse the repository at this point in the history
MC-7723 add webview auth flow
  • Loading branch information
naymushin authored Jul 20, 2023
2 parents 23c102c + feedebd commit 611521a
Show file tree
Hide file tree
Showing 29 changed files with 808 additions and 64 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
## 1.0.6
## 1.1.0

#### Fixed
#### Changes
#### Additions

- [app-demo], [tinkoff-id] Добавлен флоу авторизации через WebView MC-7723

## 1.0.5

#### Fixed
Expand Down
7 changes: 7 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Документ по миграции

## 1.0.6 -> 1.1.0

Переименованы методы класса `TinkoffIdAuth`:
- `createTinkoffAuthIntent(callbackUrl: Uri): Intent` -> `createTinkoffAppAuthIntent(callbackUrl: Uri): Intent`
- `isTinkoffAuthAvailable(): Boolean ` -> `isTinkoffAppAuthAvailable(): Boolean `
64 changes: 43 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,28 @@ Tinkoff ID - SDK для авторизации пользователей Androi
implementation "ru.tinkoff.core.tinkoffauth:tinkoff-id:${version}"
```

Так же необходимо добавить в [network-security-config](https://developer.android.com/training/articles/security-config) содержащий сертификаты от Минцифры и доп. сертификат от Тинькофф.
Пример можно посмотреть в [app-demo](app-demo). Выглядит он так:
```xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="@raw/tinkoff_root_cert" />
<certificates src="@raw/ministry_of_digital_development_root_cert" />
</trust-anchors>
</base-config>
</network-security-config>
```

## Требования к приложению

Для работы SDK необходимо следующее:

+ Зарегистрированный идентификатор авторизуемого приложения (`client_id`)
+ Uri авторизуемого клиента, на который будет выполнен редирект по завершению авторизации (`redirectUri`)
+ Зарегистрированный авторизуемым приложением [App Link](https://developer.android.com/training/app-links), который будет использоваться для возврата в приложение после авторизации. Использование deep link возможно, но не рекомендовано.
+ Зарегистрированный авторизуемым приложением [AppLink](https://developer.android.com/training/app-links), который будет использоваться для возврата в приложение после авторизации. Использование DeepLink возможно, но не рекомендовано. (`callbackUrl`)
+ Авторизация через Тинькофф будет работать только начиная с версии Android 6.0, на более ранних версиях получить авторизационные данные не будет возможности.

## Интеграция
Expand All @@ -32,19 +47,25 @@ implementation "ru.tinkoff.core.tinkoffauth:tinkoff-id:${version}"

Все необходимое взаимодействие в библиотеке идет только через класс `TinkoffIdAuth`.
Сперва проверьте, есть ли возможность пройти авторизацию через приложение Тинькофф.
Для этого используйте - `tinkoffIdAuth.isTinkoffAuthAvailable()`.
Когда флаг `isTinkoffAuthAvailable == true`, значит у пользователя установлено приложение Тинькофф, через которое можно осуществить вход.
Для этого используйте `tinkoffIdAuth.isTinkoffAppAuthAvailable()`.
Когда флаг `isTinkoffAppAuthAvailable == true`, значит у пользователя установлено приложение Тинькофф,
через которое можно осуществить вход, используя `tinkoffPartnerAuth.createTinkoffAppAuthIntent(callbackUrl)`.
Иначе можно запустить сценарий авторизации через WebView, использую `tinkoffPartnerAuth.createTinkoffWebViewAuthIntent(callbackUrl)`.

### Выполнение авторизации

Для авторизации:
1. Необходимо создать объект `TinkoffIdAuth(applicationContext, clientId, redirectUri)` - это основной класс для работы с библиотекой.
2. Запустить партнерскую авторизацию, передав ваш App/Deep link (по данному uri приложение группы Тинькофф вернется обратно после процесса авторизации)
2. На основе значения `tinkoffIdAuth.isTinkoffAppAuthAvailable()` выбрать способ авторизации. Запустить партнерскую авторизацию, передав в качестве аргумента `callbackUrl` ваш AppLink/DeepLink (по данному uri приложение группы Тинькофф вернется обратно после процесса авторизации)
```kotlin
val intent = tinkoffIdAuth.createTinkoffAuthIntent(partnerUri)
val intent = if (tinkoffPartnerAuth.isTinkoffAppAuthAvailable()) {
tinkoffPartnerAuth.createTinkoffAppAuthIntent(callbackUrl)
} else {
tinkoffPartnerAuth.createTinkoffWebViewAuthIntent(callbackUrl)
}
startActivity(intent)
```
3. После прохождения пользователем авторизации в приложении Тинькофф, произойдет переход в ваше приложение. В intent.data будет храниться информация по авторизации.
3. После прохождения пользователем авторизации в приложении Тинькофф, произойдет переход в ваше приложение на основе `callbackUrl`. В `intent.data` будет храниться информация по авторизации.

### Завершение авторизации
Успешность авторизации можно проверить методом - `tinkoffIdAuth.getStatusCode(uriFromIntentData)`. Метод вернет статус `SUCCESS` или `CANCELLED_BY_USER`
Expand All @@ -53,16 +74,16 @@ implementation "ru.tinkoff.core.tinkoffauth:tinkoff-id:${version}"
1. Нужно получить `TinkoffTokenPayload`, выполнив `getTinkoffTokenPayload(uri).getResponse()`. Данный метод необходимо выполнять в отличном от main потоке.
2. Полученный `TinkoffTokenPayload` будет содержать учетные данные пользователя

При неуспешной авторизации придет статус в intent.data `CANCELLED_BY_USER` или приложение откроется без данных в intent.data.
При неуспешной авторизации придет статус в `intent.data` `CANCELLED_BY_USER` или приложение откроется без данных в `intent.data`.

### Перевыпуск авторизационных данных

Для перевыпуска accessToken необходимо использовать метод
```kotlin
tinkoffIdAuth.obtainTokenPayload(refreshToken)
fun obtainTokenPayload(refreshToken: String): TinkoffCall<TinkoffTokenPayload>
```

В него нужно передать refreshToken, полученный ранее. Выполнять вызов `getResponse()` необходимо не на main потоке
В него нужно передать refreshToken, полученный ранее. Выполнять вызов `getResponse()` необходимо не на main потоке

### Отзыв авторизационных данных

Expand All @@ -78,7 +99,7 @@ tinkoffIdAuth.obtainTokenPayload(refreshToken)
### Хранение Refresh Token

Желательно реализовать безопасное хранение `tinkoffTokenPayload.refreshToken` в приложении,
так как он необходим для перевыпуска токенов
так как он необходим для перевыпуска токенов.

### UI

Expand Down Expand Up @@ -118,15 +139,16 @@ tinkoffIdAuth.obtainTokenPayload(refreshToken)

Базовый класс для работы c авторизацией

| Функция | Описание |
| ---------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `isTinkoffAuthAvailable(): Boolean` | Выполняет проверку возможна ли авторизация через приложения группы Тинькофф на данном устройстве |
| `createTinkoffAuthIntent(callbackUrl: Uri): Intent` | Создает Intent для открытия приложения группы Тинькофф для прохождения авторизации. На вход принимает Uri для создания AppLink/DeepLink, по которому будет осуществлен переход после окончания процесса авторизации |
| `getTinkoffTokenPayload(uri: Uri): TinkoffCall<TinkoffTokenPayload>` | Возвращает объект, который позволяет получить синхронно информацию о токене, которая придет к вам в `intent.data` после авторизации в Тинькофф |
| `getStatusCode(uri: Uri): TinkoffIdStatusCode?` | Позволяет получить статус выполнения авторизации из `intent.data` пришедшего к вам |
| `obtainTokenPayload(refreshToken: String): TinkoffCall<TinkoffTokenPayload>` | Возвращает объект, который позволяет синхронно обновить токен по рефреш токену полученному ранее |
| `signOutByAccessToken(accessToken: String): TinkoffCall<Unit>` | Возвращает объект, который позволяет синхронно разлогинить по accessToken |
| `signOutByRefreshToken(refreshToken: String): TinkoffCall<Unit>` | Возвращает объект, который позволяет синхронно разлогинить по refreshToken |
| Функция | Описание |
| ---------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `isTinkoffAppAuthAvailable(): Boolean` | Выполняет проверку возможна ли авторизация через приложения группы Тинькофф на данном устройстве |
| `createTinkoffAppAuthIntent(callbackUrl: Uri): Intent` | Создает Intent для открытия приложения группы Тинькофф для прохождения авторизации. На вход принимает Uri для создания AppLink/DeepLink, по которому будет осуществлен переход после окончания процесса авторизации |
| `createTinkoffWebViewAuthIntent(callbackUrl: Uri): Intent` | Создает Intent для открытия `TinkoffWebViewAuthActivity` для прохождения авторизации в вебе. На вход принимает Uri для создания AppLink/DeepLink, по которому будет осуществлен переход после окончания процесса авторизации |
| `getTinkoffTokenPayload(uri: Uri): TinkoffCall<TinkoffTokenPayload>` | Возвращает объект, который позволяет получить синхронно информацию о токене, которая придет к вам в `intent.data` после авторизации в Тинькофф |
| `getStatusCode(uri: Uri): TinkoffIdStatusCode?` | Позволяет получить статус выполнения авторизации из `intent.data` пришедшего к вам |
| `obtainTokenPayload(refreshToken: String): TinkoffCall<TinkoffTokenPayload>` | Возвращает объект, который позволяет синхронно обновить токен по рефреш токену полученному ранее |
| `signOutByAccessToken(accessToken: String): TinkoffCall<Unit>` | Возвращает объект, который позволяет синхронно разлогинить по accessToken |
| `signOutByRefreshToken(refreshToken: String): TinkoffCall<Unit>` | Возвращает объект, который позволяет синхронно разлогинить по refreshToken |

### TinkoffCall`<T>`

Expand Down Expand Up @@ -195,8 +217,8 @@ SDK поставляется с примером приложения, где м
В папке [app-demo](app-demo) содержится тестовое приложение.
В данном приложении можно:
- Проверить работу вашего clientId, подставив его в необходимое поле
- Посмотреть дизайн кнопки
- Авторизоваться
- Посмотреть варианты дизайна кнопки
- Авторизоваться через приложение Тинькофф или WebView
- Отозвать токены
- Обновить токены

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import kotlin.LazyThreadSafetyMode.NONE

class PartnerActivity : AppCompatActivity() {

private val partnerUri: Uri = Uri.Builder()
private val callbackUrl: Uri = Uri.Builder()
.scheme("https")
.authority("www.partner.com")
.appendPath("partner")
Expand Down Expand Up @@ -47,9 +47,13 @@ class PartnerActivity : AppCompatActivity() {
intent.data?.let { partnerPresenter.getToken(it) }

val clickListener = View.OnClickListener {
if (tinkoffPartnerAuth.isTinkoffAuthAvailable() && isDataCorrect()) {
if (isDataCorrect()) {
initTinkoffIdAuth()
val intent = tinkoffPartnerAuth.createTinkoffAuthIntent(partnerUri)
val intent = if (tinkoffPartnerAuth.isTinkoffAppAuthAvailable()) {
tinkoffPartnerAuth.createTinkoffAppAuthIntent(callbackUrl)
} else {
tinkoffPartnerAuth.createTinkoffWebViewAuthIntent(callbackUrl)
}
startActivity(intent)
}
}
Expand Down Expand Up @@ -126,7 +130,7 @@ class PartnerActivity : AppCompatActivity() {
}

fun onCancelledByUser() {
Toast.makeText(this, "Partner auth was cancelled", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "Partner authorization was cancelled", Toast.LENGTH_SHORT).show()
}

fun onAuthError() {
Expand Down
13 changes: 11 additions & 2 deletions app-demo/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
<certificates src="@raw/tinkoff_root_cert"
tools:ignore="NetworkSecurityConfig" />
<certificates src="@raw/ministry_of_digital_development_root_cert"
tools:ignore="NetworkSecurityConfig" />
</trust-anchors>
</base-config>
<debug-overrides>
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config>
</network-security-config>
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ POM_SCM_URL=https://github.com/tinkoff-mobile-tech/TinkoffID-Android/tree/main
POM_SCM_CONNECTION=scm:git:git://github.com/tinkoff-mobile-tech/TinkoffID-Android.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://github.com:tinkoff-mobile-tech/TinkoffID-Android.git

VERSION_NAME=1.0.6
VERSION_NAME=1.1.0
VERSION_CODE=7
GROUP=ru.tinkoff.core.tinkoffauth
1 change: 1 addition & 0 deletions gradle/plugin/android.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ android {
versionCode rootProject.authCode
versionName rootProject.authVersion
buildConfigField 'String', 'VERSION_NAME', "\"${rootProject.authVersion}\""
vectorDrawables.useSupportLibrary = true
}

compileOptions {
Expand Down
6 changes: 6 additions & 0 deletions tinkoff-id/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,10 @@
</intent>
</queries>

<application>
<activity android:name=".ui.webView.TinkoffWebViewAuthActivity"
android:theme="@style/TinkoffIdAuth.Theme"
android:exported="false" />
</application>

</manifest>
Loading

0 comments on commit 611521a

Please sign in to comment.