#android #oauth-2.0 #openid #android-jetpack-compose
Вопрос:
У меня действительно странная проблема со release
сборкой моего приложения. Он использует net.openid:appauth:0.7.1
библиотеку и хранит AuthState
внутри DataStore
( androidx.datastore:datastore-preferences:1.0.0-alpha06
). Вот onCreate
метод моей основной деятельности:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val authState by authViewModel.authStateFlow.collectAsState(null) AppTheme { Surface(color = MaterialTheme.colors.background) { when (authState?.isAuthorized) { true -gt; { App(authViewModel::onLogoutEvent) } false -gt; AuthScreen { authViewModel.onLoginEvent(authPageLauncher) } null -gt; {} } } } } }
Здесь приложение решает, на основе AuthState.isAuthorized
какого экрана показывать. authViewModel
берет эти данные из другого источника:
@HiltViewModel class AuthViewModel @Inject constructor( private val authStateStorage: AuthStateStorage, private val authService: AuthorizationService, private val usersRepo: UsersRepository, private val notificationsRepo: NotificationsRepository ) : ViewModel() { val authStateFlow = authStateStorage.authStateFlow // ... }
Та часть AuthStateStorage
, которая отвечает за это:
class AuthStateStorage(context: Context) { private companion object { const val AUTH_STATE_PREFS_NAME = "auth_state_prefs" val AUTH_STATE_KEY = stringPreferencesKey("auth_state_key") val USER_ID_KEY = stringPreferencesKey("user_id_key") val USER_PAYLOAD_KEY = stringPreferencesKey("user_payload_key") } private val dataStore = context.createDataStore(AUTH_STATE_PREFS_NAME) private fun Preferences.getAuthState() = this[AUTH_STATE_KEY]?.let { AuthState.jsonDeserialize(it) } ?: AuthState() val authStateFlow = dataStore.data.map { it.getAuthState() } // ... }
Можно было бы подумать , что dataStore
будет храниться вновь созданный экземпляр AuthState
, чей isAuthorized
файл находится false
. И это верно для debug
сборок.
Но когда я создаю release
apk и устанавливаю его, App
составляемый файл немедленно вызывается, вызывая исключение. У меня также есть перехватчик токенов, который я подключаю к своему клиенту OHTTP:
class TokenInterceptor @Inject constructor( private val authStateStorage: AuthStateStorage, private val authService: AuthorizationService ): Interceptor { private companion object { const val TAG = "TokenInterceptor" const val AUTH_HEADER = "Authorization" } override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() request.header(AUTH_HEADER) ?: run { request = chain.request() .newBuilder() .addHeader(AUTH_HEADER, "Bearer ${getAccessToken()}") .build() } return chain.proceed(request) } private fun getAccessToken(): String = runBlocking { val authState = authStateStorage.authStateFlow.first() val isNeedToUpdateToken = authState.needsTokenRefresh suspendCoroutine { continuation -gt; authState.performActionWithFreshTokens(authService) { accessToken, _, exception -gt; exception?.let { /* Exception occurs here */ Log.e(TAG, "Exception in token process: ", it) continuation.resumeWithException(it) } ?: run { if (isNeedToUpdateToken) { runBlocking { authStateStorage.updateAuthState(authState) } } continuation.resume(accessToken!!) } } } } }
Exception text is pretty expected:
E/TokenInterceptor: Exception in token process: AuthorizationException: {"type":2,"code":2002,"error":"invalid_grant","errorUri":""} at net.openid.appauth.AuthorizationService$TokenRequestTask.onPostExecute(AuthorizationService.java:480) at net.openid.appauth.AuthorizationService$TokenRequestTask.onPostExecute(AuthorizationService.java:395) at android.os.AsyncTask.finish(AsyncTask.java:771) at android.os.AsyncTask.access$900(AsyncTask.java:199) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Таким образом, в основном release
приложение полностью пропускает (или пропускает) проверку состояния аутентификации, а затем переходит к выполнению HTTP-запросов, как будто ничего не случилось. Но самое странное заключается в том, что если я только что установил release
сборку без ее запуска, перейдите в раздел Информация о приложении -gt; Хранилище и кэш -gt;gt; Очистить хранилищеgt;gt;, а затем запустите мое приложение, оно будет вести себя так, как задумано. Я не смог объяснить и исправить это поведение. Есть какие-нибудь идеи?