коллеги! Опишу кратко ситуацию (приготовтесь к тяжелому материалу): Есть приложение с авторизацией через сайт, средствами вот этой библиотеки AppAuth (так хочет заказчик). Так же он хочет два приложения в одном проекте (разделение выполнено через productFlavors). Проблема в том, что данные об авторизации сохраняются где-то в куках (или еще где - этого я как раз понять не могу). Если я авторизируюсь в П1, и открою П2, то после отправки запроса на сайт об авторизации, мне не будет показан экран с вводом пароля и логина (показывается он средствами бразуера смартфона). Экран пропущен, я буду считаться как уже авторизированные (ведь так оно и есть, но в П1, а не в П2 и в этом будет ошибка). Как заставить браузер забыть о том, что я авторизирован при захочет с другого приложения? (очистить куки, или еще какую магию знает кто)
Ниже я приведу участки кода:
Вызов экрана авторизации:
public void startLogin() {
AuthorizationServiceConfiguration serviceConfig =
new AuthorizationServiceConfiguration(
Uri.parse(AUTH_ENDPOINT), // authorization endpoint
Uri.parse(TOKEN_ENDPOINT)); // token endpoint
AuthorizationRequest.Builder builder = new AuthorizationRequest.Builder(
serviceConfig,
CLIENT_ID,
ResponseTypeValues.CODE,
Uri.parse(getString(R.string.app_login_callback_uri))
).setScope(APIConfig.SCOPE);
AuthorizationRequest request = builder.build();
Intent authIntent = authorizationService.getAuthorizationRequestIntent(request);
startActivityForResult(authIntent, AUTH_REQUEST_KEY);
}
Перехват результата от браузера:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != AUTH_REQUEST_KEY || resultCode != RESULT_OK) {
//LOGOUT_REQUEST_KEY is called when leaving logout webview
//if logout webview is cancelled or back button is closed, result value is 0
resetViewState();
return;
}
AuthorizationResponse response = AuthorizationResponse.fromIntent(data);
AuthorizationException error = AuthorizationException.fromIntent(data);
if (response == null) {
handleLoginError(getString(R.string.login_screen_error_login_cancelled));
return;
}
final AuthState authState = new AuthState(response, error);
authorizationService.performTokenRequest(response.createTokenExchangeRequest(), (tokenResponse, exception) -> {
if (exception != null) {
Log.e(TAG, "Token Exchange failed", exception);
exception.printStackTrace();
handleLoginError(getString(R.string.login_screen_error_token_request_failed));
return;
//handleLoginError(exception.getMessage());
}
if (tokenResponse != null) {
authState.update(tokenResponse, null);
if (BuildConfig.FLAVOR_role.equalsIgnoreCase("manager")) {
if (authState.getAccessToken() != null) {
JWT jwt = new JWT(authState.getAccessToken());
Claim manager = jwt.getClaim("role");
List<String> roles = manager.asList(String.class);
boolean isManager = roles.contains("manager") || roles.contains("\"manager\"");
if (!isManager) {
Toast.makeText(getApplicationContext(), "Access denied", Toast.LENGTH_SHORT).show();
binding.setIsLoading(false);
return;
}
}
}
AuthStateHelper.saveAuthState(
getBaseContext(),
authState.getAccessToken(),
authState.getIdToken(),
authState.getRefreshToken());
showHomepage();
return;
/*
Log.i(TAG,"Auth state: "+authStateString);
String authStateString = authState.jsonSerializeString();
Log.i(TAG,
String.format("Token Response [ Access Token: %s, ID Token: %s , Refresh Token: %s]",
tokenResponse.accessToken, tokenResponse.idToken, tokenResponse.refreshToken));*/
}
handleLoginError(getString(R.string.login_screen_error_token_request_failed));
});
}
Сохранение токенов (и прочей прихоядщей информации о авторизации) я сохраняю в shared Preference. там я тоже реализовал раздельное хранение, но неожиданно это не помогло. В связи с этим, я предположил, что сохранение данных происходит в самом бразуре или сервере (но скорее всего браузере). Если приложение удалить, и установить заново - то придется вводить пользовательские данные. Если разлогиниться, то выкенет на экран авторизации в обоих приложениях.
ПРАВКА: applicationId Для обоих приложений разный:
flavorDimensions 'env', 'role'
productFlavors {
daily {
dimension 'role'
applicationId = "com.xxx.aaa"
proguardFile 'proguard-rules.pro'
}
manager {
dimension 'role'
applicationId = "com.xxx.aaa.manager"
proguardFile 'proguard-rules-manager.pro'
}
dev {
dimension 'env'
applicationIdSuffix ".dev"
manifestPlaceholders = [
'appAuthRedirectScheme': 'com.xxx.aaa.dev'
]
}
live {
dimension 'env'
manifestPlaceholders = [
'appAuthRedirectScheme': 'com.xxx.aaa'
]
}
}
А так же привожу AuthStateHelper:
public class AuthStateHelper {
public static void saveAuthState(Context context,
String accessToken,
String idToken,
String refreshToken) {
String IVString = null;
String encryptedRefreshToken = null;
String newAuthStateString = null;
EncryptionHandler handler = new EncryptionHandler(context);
byte[] IV = handler.generateIV();
IVString = Base64.encodeToString(IV, Base64.NO_WRAP);
encryptedRefreshToken = new EncryptionHandler(context).encryptValue(IV, refreshToken);
//newAuthStateString = AuthStateHelper.removeRefreshToken(authState.jsonSerializeString());
//SharedPrefsUtils.saveAuthState(context, newAuthStateString);
SharedPrefsUtils.saveIV(context, IVString);
SharedPrefsUtils.saveRefreshToken(context, encryptedRefreshToken);
SharedPrefsUtils.saveIdToken(context, idToken);
SharedPrefsUtils.saveAccessToken(context, accessToken);
}
/**
* Load saved auth state and add refresh token to auth state after decrypting it
*
* @param context Context
* @return Auth state
*/
public static String getRefreshToken(Context context) {
String IV = SharedPrefsUtils.getIV(context);
String encryptedRefreshToken = SharedPrefsUtils.getRefreshToken(context);
EncryptionHandler handler = new EncryptionHandler(context);
return handler.decryptValue(encryptedRefreshToken, IV);
}
}
ПРАВКА № 2 Продебажил авторизацию, с целью изучения токенов. Использовал https://jwt.io/ . Получилось, что ответ возвращаемый сервером содержит одни поля. Ниже привожу accessToken cо слегка измененными. Для обоих приложений токены одинаковые, за исключение двух первых полей. Я увидел там несколько видов id, но как их настриоть?)
Как я уже говорил, SharedPrefsUtils разделены для обоих приложений. Надеюсь, вы сможете еще что-то мне посоветовать
Без наличия AuthStateHelper предположу, что оба приложения подписаны одним ключом, поэтому читают одни и те же настройки - старый токен из другого приложения.
Выложите helper, build.gradle (меняете или нет applicationId и т.д.)
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Подскажите, где может быть проблема: Имею сервер, к которому соединяются устройства по tcp socket, на каждое красиво создаётся потокСоединившись,...
Выдаёт ошибку при компилиции, пока не дошел до switch всё идёт нормально, а потом ошибкаГде моя ошибка?
Здравствуйте кидает Exception ConcurrentModificationException на этой строчке for (Transaction t : cgetTransactions())(64 строчка) на 2 итерации
Есть проект на JavaFX, для хранения данных нужно использовать сериализацию в JAXBДля этого нужно использовать XML