Natknąłem się na ten sam problem podczas programowania backendu z Spring Boot i OAuth2. Problem, z którym się spotkałem, polegał na tym, że jeśli wiele urządzeń współużytkuje te same tokeny, gdy jedno urządzenie odświeży token, drugie urządzenie będzie pozbawione pojęcia i, mówiąc krótko, oba urządzenia weszły w szał odświeżania tokena. Moim rozwiązaniem było zastąpienie domyślnej AuthenticationKeyGenerator
niestandardową implementacją, która zastępuje DefaultAuthenticationKeyGenerator
i dodaje nowy parametr client_instance_id
w mieszaninie generatorów kluczy. Następnie moi klienci mobilni wysyłaliby ten parametr, który musi być unikalny dla wszystkich instalacji aplikacji (iOS lub Android). Nie jest to szczególny wymóg, ponieważ większość aplikacji mobilnych już śledzi instancję aplikacji w jakiejś formie.
public class EnhancedAuthenticationKeyGenerator extends DefaultAuthenticationKeyGenerator {
public static final String PARAM_CLIENT_INSTANCE_ID = "client_instance_id";
private static final String KEY_SUPER_KEY = "super_key";
private static final String KEY_CLIENT_INSTANCE_ID = PARAM_CLIENT_INSTANCE_ID;
@Override
public String extractKey(final OAuth2Authentication authentication) {
final String superKey = super.extractKey(authentication);
final OAuth2Request authorizationRequest = authentication.getOAuth2Request();
final Map<String, String> requestParameters = authorizationRequest.getRequestParameters();
final String clientInstanceId = requestParameters != null ? requestParameters.get(PARAM_CLIENT_INSTANCE_ID) : null;
if (clientInstanceId == null || clientInstanceId.length() == 0) {
return superKey;
}
final Map<String, String> values = new LinkedHashMap<>(2);
values.put(KEY_SUPER_KEY, superKey);
values.put(KEY_CLIENT_INSTANCE_ID, clientInstanceId);
return generateKey(values);
}
}
które następnie wstrzyknąłbyś w podobny sposób:
final JdbcTokenStore tokenStore = new JdbcTokenStore(mDataSource);
tokenStore.setAuthenticationKeyGenerator(new EnhancedAuthenticationKeyGenerator());
Żądanie HTTP wyglądałoby wtedy mniej więcej tak
POST /oauth/token HTTP/1.1
Host: {{host}}
Authorization: Basic {{auth_client_basic}}
Content-Type: application/x-www-form-urlencoded
grant_type=password&username={{username}}&password={{password}}&client_instance_id={{instance_id}}
Zaletą korzystania z tego podejścia jest to, że jeśli klient nie wyśle a client_instance_id
, zostanie wygenerowany klucz domyślny, a jeśli wystąpi instancja, ten sam klucz jest zwracany za każdym razem dla tej samej instancji. Ponadto klucz jest niezależny od platformy. Minusem byłoby to, że skrót MD5 (używany wewnętrznie) jest wywoływany dwa razy.