Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Авторизация VK в связке с Firebase

#android #вконтакте #firebase


Необходимо реализовать авторизацию в андроид приложении через VK в связке через Firebase
без использования собственного сервера. 

Поиск советует сделать через https://auth0.com/ сервис, но непонятно каким образом?
Кто-нибудь реализовывал данную схему, как?
    


Ответы

Ответ 1



UPD: код, указанный ниже, был использован с VK SDK ~1.6.7. Код с использованием текущей версии SDK(2.0.0+) может во многом отличаться от приведенного в примере - в частности, потому, что класс VKAccessToken был переписан и поля email теперь предположительно нет в открытом доступе. Однако решение есть: https://github.com/VKCOM/vk-android-sdk/issues/399 В виду того, что прошло достаточно много времени, а предложений не наблюдается, поделюсь своим видением решения данного вопроса (на самом деле, похоже на простенький "хак" и занимает на 5-10 строк больше, чем "чистая" авторизация с Firebase). А именно, sample Activity, из которого будет видно, что вместо того, чтобы пытаться синхронизировать оба сервиса на некоем высоком уровне, мы просто посылаем credentials ВК-юзера на сервер Firebase в виде связки email-password, добавляя щепотку соли в виде префикса "vk" (или чего по вкусу) в поле password и того же незахешированного префикса, например, в поле email для последующей идентификации провайдера в списке Firebase-юзеров. По идее, подобный механизм будет работать в связке с применением любого не-дефолтного по версии Firebase сервиса, который предоставляет собственный механизм аутентификации и, как результат, сессионные данные пользователя. Плюс такого решения в том, что в Firebase-password, который нужно передать для успешного использования ВК-креденшлов и который лично мне, например, ну совсем не нужен для личных целей, а нужен исключительно для определения identity этого и только этого ВК-юзера, можно запихнуть любую информацию по вкусу и которую только можно вытянуть из VKAccessToken(в случае данного конкретного провайдера). Вот как это может выглядеть с использованием vk android sdk - ведь, как я предполагаю, именно этот инструмент имелся в виду при создании вопроса(код на Kotlin, по запросу могу переписать на Java): class VkontakteSignInActivity : AppCompatActivity() { private var isResumed = false companion object { private val scopeArray = arrayOf(VKScope.EMAIL) private val TAG = "VkontakteSignInActivity" } private lateinit var loginProgressBar: ProgressBar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_sign_in_vkontakte) loginProgressBar = findViewById(R.id.login_progress_bar) vkontakteLoginButton.setOnClickListener { signIn() } VKSdk.wakeUpSession(this, object : VKCallback { override fun onResult(res: VKSdk.LoginState) { if (isResumed) { when (res) { VKSdk.LoginState.LoggedOut -> { //Теоретически, здесь мы дергаем свою Sign In Button //и оказываемся в теле функции signIn() } VKSdk.LoginState.LoggedIn -> {} VKSdk.LoginState.Pending -> {} VKSdk.LoginState.Unknown -> {} } } } override fun onError(error: VKError) { Log.d(TAG, error.errorMessage) Toast.makeText(this@VkontakteSignInActivity, "Session failed.", Toast.LENGTH_SHORT).show() } }) } private fun signIn(){ loginProgressBar.show() // Вызываем VKSdk.login для дальшейшего onActivityResult(), который нам понадобится VKSdk.login(this@VkontakteSignInActivity, *scopeArray) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { val callback = object : VKCallback { override fun onResult(res: VKAccessToken) { //Собственно, вся "магия" имеет место далее. //Здесь может быть любая логика по подготовке нужных //креденшлов для последующей отправки на Firebase. val authPass = preparePassForAuth(res.userId) //Когда данные готовы, получаем instance FirebaseAuth, ведь дальше без него никак, //и, собственно, создаем корневой коллбек на регистрацию/аутентификацию //пользовательских данных, которые понадобятся нам для учета. FirebaseAuth.getInstance() .fetchProvidersForEmail("vk_${res.email}") .addOnCompleteListener { task -> //Если находим хотя бы одного провайдера с существующими креденшлами, //логиним пользователя. Иначе, регистрируем его в Firebase Auth. if(task.isSuccessful && task.result.providers != null){ if (task.result.providers!!.isNotEmpty()){ firebaseAuthManager.getAuthInstance() //Не забываем предварительно трансформировать данные в "email-password" .signInWithEmailAndPassword("vk${res.email}", authPass) .addOnCompleteListener(this@VkontakteSignInActivity) { innerTask -> processAuthResult(innerTask, authPass) } } else { firebaseAuthManager.getAuthInstance() //Не забываем предварительно трансформировать данные в "email-password" .createUserWithEmailAndPassword("vk${res.email}", authPass) .addOnCompleteListener(this@VkontakteSignInActivity) { innerTask -> processAuthResult(innerTask, authPass) } } } else { //На случай unsuccessful response от самого Firebase'овского сервиса Log.w(TAG, "FirebaseAuth:failure", task.exception) Toast.makeText(this@VkontakteSignInActivity, "Authentication failed.", Toast.LENGTH_SHORT).show() } } } override fun onError(error: VKError) { loginProgressBar.hide() Log.d(TAG, error.errorMessage) Toast.makeText(this@VkontakteSignInActivity, "Authentication failed.", Toast.LENGTH_SHORT).show() } } if (!VKSdk.onActivityResult(requestCode, resultCode, data, callback)) { super.onActivityResult(requestCode, resultCode, data) } } fun processAuthResult(innerTask: Task, authPass: String) { //Обрабатываем внутренний AuthResult'овский коллбек //в зависимости от нужд. Если все ок, делаем свои дела. if (innerTask.isSuccessful) { vkontakteLoginButton.hide() loginProgressBar.hide() startActivity(Intent(this@VkontakteSignInActivity, MainActivity::class.java)) } else { //На случай auth failure Firebase'овского сервиса Log.w(TAG, "createUpdateUserWithEmail:failure", task.exception) Toast.makeText(this@VkontakteSignInActivity, "Authentication failed.", Toast.LENGTH_SHORT).show() } } fun preparePassForAuth(userId: String): String { //Код для хеширования UID, например } fun getVKUIdFromPass(hashedPass: String): String { //Код для расшифровки UID, например } } Естественно, для того, чтобы эта связка работала, необходимо включить Способ входа "Адрес электронной почты и пароль" в Firebase Auth - консоли. После включения я, например, дефолтных поднастроек не менял - все работает, как есть. UPD: добавил немного кода для большей наглядности процессов создания новых, определения уже существующих Firebase'овских аккаунтов и ошибок, которые могут возникать в процессе комплексного запроса.

Комментариев нет:

Отправить комментарий