我正在使用Retrofit 2.3.0与使用JWT从Spring Boot应用程序进行身份验证的API进行通信。
为了使其有效,我创建了一个Interceptor
实现:
private static class JwtAuthenticationInterceptor implements Interceptor {
private Supplier<String> jwtTokenSupplier;
private JwtAuthenticationInterceptor(Supplier<String> jwtTokenSupplier) {
this.jwtTokenSupplier = jwtTokenSupplier;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("Authorization",
String.format("Bearer %s", jwtTokenSupplier.get()));
Request request = builder.build();
return chain.proceed(request);
}
}
在我的Spring服务中,我让Retrofit在构造函数中创建API接口的实例:
public MySringServiceImpl() {
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(createLoggingInterceptor())
.addInterceptor(new JwtAuthenticationInterceptor(this::createJwtToken))
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://my.remoteapi.com/api/")
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build();
api = retrofit.create(MyRemoteApi.class);
}
所以在我的服务的实际方法中,我使用这样的东西:
public List<Stuff> getStuffFromApi() {
try {
List<Stuff> response = api.getStuff().execute().body();
if (response != null) {
return response;
} else {
return new ArrayList<>();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
createJwtToken
方法创建JWT令牌(使用Java JWT library)
private String createJwtToken() {
return Jwts.builder()
.setIssuer("http://my.remoteapi.com/api/")
.setId("my-test-id")
.setIssuedAt(new Date())
.setExpiration(new Date(ZonedDateTime.now().plusSeconds(60).toEpochSecond() * 1000))
.claim("uid", "123")
.signWith(SignatureAlgorithm.HS512,
"my-very-secret-key"
.getBytes())
.compact();
}
实际问题:
uid
声明需要包含当前用户的ID(而不是像现在这样硬编码)。我很清楚如何在RestController中获取Spring主体并将其传递给服务,但是我如何指示拦截器使用该主体的id来进行正在进行的调用?我应该为每个调用创建一个新的Retrofit实例,还是有更好的方法来处理它?</ p>