使用匕首 2 时 JWT 令牌不会更新?
JWT Token Wont Update when using dagger 2?
我在运行时使用 dagger 2 更新令牌时遇到问题。
场景是这样的:
我有一个更改密码的屏幕。当我成功更新密码时,当前的 jwt 令牌将无效,我需要从更新令牌响应中存储新令牌,我将该令牌存储在 SharedPreferences 中。但问题是当我存储令牌时。它在 sharedprefernces 中更新,但不会在我构建 Retrofit 实例的 DaggerGraph 中更新值(授权 header)。
下面是我的代码:
AppComponent.kt
@Singleton
@Component(
modules = [StorageModule::class, AppModule::class, ViewModelModule::class]
)
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): AppComponent
}
fun inject(activity: SplashActivity)
fun inject(activity: LoginActivity)
fun inject(activity: MainActivity)
fun inject(activity: ChangePasswordActivity)
}
AppModule.kt
@Module
class AppModule {
@Singleton
@Provides
fun provideAuthInterceptor(sharedPreferencesSources: SharedPreferencesSources): Interceptor {
return AuthInterceptor(sharedPreferencesSources.tokenApi())
}
@Singleton
@Provides
fun provideApiService(
authInterceptor: Interceptor
): SharedProductClient {
return Network.retrofitClient(authInterceptor = authInterceptor)
.create(SharedProductClient::class.java)
}
@Singleton
@Provides
fun provideAppRepository(apiService: SharedProductClient): AppRepository {
return AppRepositoryImpl(apiService)
}
@Singleton
@Provides
fun provideAppUseCase(appRepository: AppRepository): AppUseCase {
return AppUseCase(appRepository)
}
@Singleton
@Provides
fun provideAppScheduler(): SchedulerProvider = AppSchedulerProvider()
}
StorageModule.kt
@Module
class StorageModule {
@Singleton
@Provides
fun provideSharedPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(SharedPrefName, Context.MODE_PRIVATE)
}
@Singleton
@Provides
fun provideSharedPreferencesSource(sharedPrefInstance: SharedPreferences): SharedPreferencesSources {
return SharedPreferencesSourcesImpl(sharedPrefInstance)
}
companion object {
const val SharedPrefName = "share_product_prefs"
}
}
AuthInterceptor.kt
class AuthInterceptor constructor(
private val token: String
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.run {
proceed(
request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer $token")
.build()
)
}
}
任何建议都会对我有帮助。谢谢!
这是因为您在创建 AuthInterceptor
时只传递了令牌的 String
实例。
您应该提供一种在需要时从 SharedPreferences
动态获取令牌的方法(例如接口)。
这是一种方法:
- 将
token:String
更改为 AuthInterceptor
构造函数中的函数类型(并在需要时使用它):
class AuthInterceptor constructor(
private val tokenProvider: () -> String
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.run {
proceed(
request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer ${tokenProvider.invoke()}")
.build()
)
}
}
- 创建
AuthInteceptor
时构建 lambda 以动态引用 SharedPreferences
@Module
class AppModule {
@Singleton
@Provides
fun provideAuthInterceptor(sharedPreferencesSources: SharedPreferencesSources): Interceptor {
return AuthInterceptor(){ sharedPreferencesSources.tokenApi() }
}
//...
}
这样,每次您进行 api 调用时,tokenProvider
将是 invoked
(将访问 SharedPreferences
),而不是在创建时只调用一次AuthInterceptor
.
我在运行时使用 dagger 2 更新令牌时遇到问题。
场景是这样的:
我有一个更改密码的屏幕。当我成功更新密码时,当前的 jwt 令牌将无效,我需要从更新令牌响应中存储新令牌,我将该令牌存储在 SharedPreferences 中。但问题是当我存储令牌时。它在 sharedprefernces 中更新,但不会在我构建 Retrofit 实例的 DaggerGraph 中更新值(授权 header)。
下面是我的代码:
AppComponent.kt
@Singleton
@Component(
modules = [StorageModule::class, AppModule::class, ViewModelModule::class]
)
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): AppComponent
}
fun inject(activity: SplashActivity)
fun inject(activity: LoginActivity)
fun inject(activity: MainActivity)
fun inject(activity: ChangePasswordActivity)
}
AppModule.kt
@Module
class AppModule {
@Singleton
@Provides
fun provideAuthInterceptor(sharedPreferencesSources: SharedPreferencesSources): Interceptor {
return AuthInterceptor(sharedPreferencesSources.tokenApi())
}
@Singleton
@Provides
fun provideApiService(
authInterceptor: Interceptor
): SharedProductClient {
return Network.retrofitClient(authInterceptor = authInterceptor)
.create(SharedProductClient::class.java)
}
@Singleton
@Provides
fun provideAppRepository(apiService: SharedProductClient): AppRepository {
return AppRepositoryImpl(apiService)
}
@Singleton
@Provides
fun provideAppUseCase(appRepository: AppRepository): AppUseCase {
return AppUseCase(appRepository)
}
@Singleton
@Provides
fun provideAppScheduler(): SchedulerProvider = AppSchedulerProvider()
}
StorageModule.kt
@Module
class StorageModule {
@Singleton
@Provides
fun provideSharedPreferences(context: Context): SharedPreferences {
return context.getSharedPreferences(SharedPrefName, Context.MODE_PRIVATE)
}
@Singleton
@Provides
fun provideSharedPreferencesSource(sharedPrefInstance: SharedPreferences): SharedPreferencesSources {
return SharedPreferencesSourcesImpl(sharedPrefInstance)
}
companion object {
const val SharedPrefName = "share_product_prefs"
}
}
AuthInterceptor.kt
class AuthInterceptor constructor(
private val token: String
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.run {
proceed(
request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer $token")
.build()
)
}
}
任何建议都会对我有帮助。谢谢!
这是因为您在创建 AuthInterceptor
时只传递了令牌的 String
实例。
您应该提供一种在需要时从 SharedPreferences
动态获取令牌的方法(例如接口)。
这是一种方法:
- 将
token:String
更改为AuthInterceptor
构造函数中的函数类型(并在需要时使用它):
class AuthInterceptor constructor(
private val tokenProvider: () -> String
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response = chain.run {
proceed(
request()
.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer ${tokenProvider.invoke()}")
.build()
)
}
}
- 创建
AuthInteceptor
时构建 lambda 以动态引用SharedPreferences
@Module
class AppModule {
@Singleton
@Provides
fun provideAuthInterceptor(sharedPreferencesSources: SharedPreferencesSources): Interceptor {
return AuthInterceptor(){ sharedPreferencesSources.tokenApi() }
}
//...
}
这样,每次您进行 api 调用时,tokenProvider
将是 invoked
(将访问 SharedPreferences
),而不是在创建时只调用一次AuthInterceptor
.