Сохранение сессии Telegram API

422
13 марта 2018, 02:33

Приветствую.

Возник вопрос по поводу Telegram API (не Bot API). Не могу понять, как сохранить данные пользователя после его первой аутентификации в приложении. В данный момент при каждом входе идет запрос кода.

После первого удачного входа пробовал сохранять phoneCodeHash, номер телефона и phoneCode. В принципе, это работает до истечения срока кода аутентификации.

Возможно, сейчас я путаю, потому что использую представление данного API на Java с библиотекой Kotlogram. Реализация аутентификации в сэмпле:

ApiStorage.java

public static class ApiStorage implements TelegramApiStorage {
//Create File variable for auth.key and dc.save
public static final File AUTH_KEY_FILE = new File("Properties/auth.key");
public static final File NEAREST_DC_FILE = new File("Properties/dc.save");
@Override
public void saveAuthKey(@NotNull AuthKey authKey) {
    try {
        FileUtils.writeByteArrayToFile(AUTH_KEY_FILE, authKey.getKey());
    } catch (IOException e) {
        e.printStackTrace();
    }
}
@Nullable
@Override
public AuthKey loadAuthKey() {
    try {
        return new AuthKey(FileUtils.readFileToByteArray(AUTH_KEY_FILE));
    } catch (IOException e) {
        if (!(e instanceof FileNotFoundException))
            e.printStackTrace();
    }
    return null;
}
@Override
public void saveDc(@NotNull DataCenter dataCenter) {
    try {
        FileUtils.write(NEAREST_DC_FILE, dataCenter.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}
@Nullable
@Override
public DataCenter loadDc() {
    try {
        String[] infos = FileUtils.readFileToString(NEAREST_DC_FILE).split(":");
        return new DataCenter(infos[0], Integer.parseInt(infos[1]));
    } catch (IOException e) {
        if (!(e instanceof FileNotFoundException))
            e.printStackTrace();
    }
    return null;
}
@Override
public void deleteAuthKey() {
    try {
        FileUtils.forceDelete(AUTH_KEY_FILE);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
@Override
public void deleteDc() {
    try {
        FileUtils.forceDelete(NEAREST_DC_FILE);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
@Override
public void saveSession(@Nullable MTSession session) {
}
@Nullable
@Override
public MTSession loadSession() {
    return null;
}
}

Сама аутентификация в Java Console.

public class Main {
// Get them from Telegram's console
public static final int API_ID = api id;
public static final String API_HASH = api hash;
// What you want to appear in the "all sessions" screen
public static final String APP_VERSION = "AppVersion";
public static final String MODEL = "Model";
public static final String SYSTEM_VERSION = "SysVer";
public static final String LANG_CODE = "en";
public static TelegramApp application = new TelegramApp(API_ID, API_HASH, MODEL, SYSTEM_VERSION, APP_VERSION, LANG_CODE);
public static final String PHONE_NUMBER = "тут был телефон"; // International format
public static void main(String[] args) {
    TelegramClient client = Kotlogram.getDefaultClient(application, new ApiStorage());
    try {
        TLSentCode sentCode = client.authSendCode(false, PHONE_NUMBER, true);
        System.out.println("Authentication code: ");
        String code = new Scanner(System.in).nextLine();
        TLAuthorization authorization = client.authSignIn(PHONE_NUMBER, sentCode.getPhoneCodeHash(), code);
        TLUser self = authorization.getUser().getAsUser();
        System.out.println("You are now signed in as " + self.getFirstName() + " " + self.getLastName() + " @" + self.getUsername());
    } catch (RpcErrorException | IOException e) {
        e.printStackTrace();
    } finally {
        client.close(); // Important, do not forget this, or your process won't finish
    }
}
}

Данную реализацию я использую в Android приложении. Конечно, все раскидано по асинхронным потокам. Но каждый раз при входе в приложение идет проверка кода авторизации. Из-за этого я за сегодня заблокировал 3 разных аккаунта на день по причине флуда авторизации.

В качестве обходного варианта я использовал подстановку значений в данном методе, запоминая их при удачной авторизации.

client.authSignIn(phoneNumber, phoneCodeHash, phoneCode);

Это работает только до того момента, пока код не истечет. Возможно, кто-то знает как это решается на уровне самого API, а не библиотеки, или сможет предложить вариант использования других подходов для работы с Telegram API: стандартный API, TDlib или какое-либо другое решение для авторизации пользователей в приложении через Telegram на Java.

Честно, не смог ни с чем другим разобраться. Заранее благодарю за ответы.

Answer 1

Нашел решение методом научного тыка. Я был действительно не прав, т.к. данная библиотека сама умеет отрабатывать сессии. Просто делает это (на мой взгляд) очень неочевидно. Прикладываю ниже рабочее решение в виде консольного приложения на Java. Это же решение работает и для Android приложения.

public class Main {
    // Get them from Telegram's console
    private static final int API_ID = /*put api id here*/;
    private static final String API_HASH = "put hash here";
    // What you want to appear in the "all sessions" screen
    private static final String APP_VERSION = "AppVersion";
    private static final String MODEL = "Model";
    private static final String SYSTEM_VERSION = "SysVer";
    private static final String LANG_CODE = "en";
    private static TelegramApp application = new TelegramApp(API_ID, API_HASH, MODEL, SYSTEM_VERSION, APP_VERSION, LANG_CODE);
    private static final String PHONE_NUMBER = "put a phone number here"; // International format
    public static void main(String[] args) {
        TelegramClient client = Kotlogram.getDefaultClient(application, new ApiStorage());
        try {
            TLUserFull userFull = client.usersGetFullUser(new TLInputUserSelf());
            TLUser self = userFull.getUser().getAsUser();
            showUserInfo(self);
        } catch (RpcErrorException e) {
            if (e.getTag().equals("AUTH_KEY_UNREGISTERED"))
                signInUser(client);
            else
                e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            client.close();
        }
    }
    private static void signInUser(TelegramClient client) {
        try {
            // Send code to account
            TLSentCode sentCode = client.authSendCode(false, PHONE_NUMBER, true);
            System.out.println("Authentication code: ");
            String code = new Scanner(System.in).nextLine();
            TLAuthorization authorization = client.authSignIn(PHONE_NUMBER, sentCode.getPhoneCodeHash(), code);
            TLUser self = authorization.getUser().getAsUser();
            showUserInfo(self);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void showUserInfo(TLUser user) {
        System.out.println("You are now signed in as " + user.getFirstName() + " " + user.getLastName() + " @" + user.getUsername());
    }
}

Не знаю, кто плюсовал данный вопрос, но, надеюсь, что оно кому-нибудь поможет. Спасибо.

READ ALSO
Как прочесть значение из JSON на Java?

Как прочесть значение из JSON на Java?

Как извлечь в переменную типа int число 2 из JSON-ответа на языке JAVA ? (вместо 2 может быть любое многозначное число)

227
Вопрос про авторизацию FireBase

Вопрос про авторизацию FireBase

Мне нужно сделать авторизацию по номеру телефонаВ принципе с задачей я уже справился следующим образом:

181
Значения перечисления в switch-case блоке

Значения перечисления в switch-case блоке

У меня есть простое перечисление:

157
Сравнение строк из базы данных с переменной (SQLite)

Сравнение строк из базы данных с переменной (SQLite)

Подскажите пожалуйста, пишу приложение на андроид и есть необходимость вытащить строку с определённым строковым значением которое задано...

184