重用现有令牌,而不是在 spring boot + Retrofit app 中的每个请求中请求它

Reuse existing token rather than requesting it on every request in spring boot + Retrofit app

我有一个 spring 启动应用程序,它使用 Retrofit 向安全服务器发出请求。

我的终点:

public interface ServiceAPI {

    @GET("/v1/isrcResource/{isrc}/summary")
    Call<ResourceSummary> getResourceSummaryByIsrc(@Path("isrc") String isrc);

}

public interface TokenServiceAPI {

    @FormUrlEncoded
    @POST("/bbcb6b2f-8c7c-4e24-86e4-6c36fed00b78/oauth2/v2.0/token")
    Call<Token> obtainToken(@Field("client_id") String clientId,
                            @Field("scope") String scope,
                            @Field("client_secret") String clientSecret,
                            @Field("grant_type") String grantType);

}

配置class:

@Bean
Retrofit tokenAPIFactory(@Value("${some.token.url}") String tokenUrl) {
    Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(tokenUrl)
            .addConverterFactory(JacksonConverterFactory.create());
    return builder.build();
}

@Bean
Retrofit serviceAPIFactory(@Value("${some.service.url}") String serviceUrl, TokenServiceAPI tokenAPI) {
    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .addInterceptor(new ServiceInterceptor(clientId, scope, clientSecret, grantType, apiKey, tokenAPI))
            .build();

    Retrofit.Builder builder = new Retrofit.Builder()
            .baseUrl(repertoireUrl)
            .client(okHttpClient)
            .addConverterFactory(JacksonConverterFactory.create());
    return builder.build();
}

为每个请求添加授权header的拦截器

public class ServiceInterceptor implements Interceptor {

    public ServiceInterceptor(String clientId,
                                        String scope,
                                        String clientSecret,
                                        String grantType,
                                        String apiKey,
                                        TokenServiceAPI tokenAPI) {
        this.clientId = clientId;
        this.scope = scope;
        this.clientSecret = clientSecret;
        this.grantType = grantType;
        this.apiKey = apiKey;
        this.tokenAPI = tokenAPI;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request newRequest = chain.request().newBuilder()
                .addHeader(AUTHORIZATION_HEADER, getToken())
                .addHeader(API_KEY_HEADER, this.apiKey)
                .build();
        return chain.proceed(newRequest);
    }

    private String getToken() throws IOException {
        retrofit2.Response<Token> tokenResponse = repertoireTokenAPI.obtainToken(clientId, scope, clientSecret, grantType).execute();
        String accessToken = "Bearer " + tokenAPI.body().getAccessToken();
        return accessToken;
    }

}

这按预期工作,问题是为每个请求请求令牌而不是使用现有的有效请求。如何将令牌存储在某处并 re-use 它?我想知道 Retrofit 是否有 built-in 解决方案。

一个可能的缓存选项:

添加咖啡因

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

在返回令牌的方法上添加@Cacheable("your-token-cache-name"),看起来像上面的getToken

application.yml中添加最大缓存大小和过期配置 例如500 个条目和 10 分钟以下配置

spring.cache.cache-names=your-token-cache-name
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s

示例来自:https://www.javadevjournal.com/spring-boot/spring-boot-with-caffeine-cache/