简体   繁体   中英

Refresh OAuth token with jersey 2 client

I'm currently migrating an application from jersey 1 to 2. In the old app, we used a ClientFilter for all jersey clients that automatically refreshed expired OAuth tokens like this:

@Override
public ClientResponse handle(ClientRequest cr) {
  ClientResponse resp = getNext().handle(cr);
  if (resp.getStatus() == Status.UNAUTHORIZED.getStatusCode()) {
    // Try to refresh the token
    boolean refreshed = refreshToken(oAuthInfo);
    if (refreshed) {
      resp = getNext().handle(cr);
    }
  }
  return resp;
}

It might not haven been the most elegant way, but the benefit was that rest client users did not have to care about expired tokens themselves.

With the ContainerResponseFilter for jersey 2, this does not seem to be that simple anymore. The only option I currently see is to use the ClientRequestContext and try to re-create the original request using getClient , getHeaders etc... and then update the result in ContainerResponseContext . This however seems a bit clunky so I was wondering if there is any more convenient way to refresh an OAuth token without having to deal with this wherever a jersey client is used?

It looks like there is not more convenient way than intercepting the response with a client filter, refreshing the token if needed and trying to repeat the exact same request with the new token. In fact, this approach is also used by jersey own filter classes.

Sample code for repeating the original rest call from within a filter class can be found in jerseys HttpAuthenticationFilter :

static boolean repeatRequest(ClientRequestContext request, ClientResponseContext response, String newAuthorizationHeader) {
    Client client = request.getClient();

    String method = request.getMethod();
    MediaType mediaType = request.getMediaType();
    URI lUri = request.getUri();

    WebTarget resourceTarget = client.target(lUri);

    Invocation.Builder builder = resourceTarget.request(mediaType);

    MultivaluedMap<String, Object> newHeaders = new MultivaluedHashMap<String, Object>();

    for (Map.Entry<String, List<Object>> entry : request.getHeaders().entrySet()) {
        if (HttpHeaders.AUTHORIZATION.equals(entry.getKey())) {
            continue;
        }
        newHeaders.put(entry.getKey(), entry.getValue());
    }

    newHeaders.add(HttpHeaders.AUTHORIZATION, newAuthorizationHeader);
    builder.headers(newHeaders);

    builder.property(REQUEST_PROPERTY_FILTER_REUSED, "true");

    Invocation invocation;
    if (request.getEntity() == null) {
        invocation = builder.build(method);
    } else {
        invocation = builder.build(method,
                Entity.entity(request.getEntity(), request.getMediaType()));
    }
    Response nextResponse = invocation.invoke();

    if (nextResponse.hasEntity()) {
        response.setEntityStream(nextResponse.readEntity(InputStream.class));
    }
    MultivaluedMap<String, String> headers = response.getHeaders();
    headers.clear();
    headers.putAll(nextResponse.getStringHeaders());
    response.setStatus(nextResponse.getStatus());

    return response.getStatus() != Response.Status.UNAUTHORIZED.getStatusCode();
}

This code is used for example in DigestAuthenticator or BasicAuthenticator to repeat a request with provided credentials in case an Unauthorised response is received from server.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM