Wiele tokenów dostępu Oauth2

13

Mam interfejs API, który wykorzystuje oAuth2 i własne aplikacje mobilne, które używają tego interfejsu API jako zaplecza. Ponieważ użytkownicy mogą być zalogowani jednocześnie za pomocą wielu urządzeń (np. IPhone'a, iPada, tabletu z Androidem lub telefonu z Androidem), potrzebuję interfejsu API do rozróżnienia każdego połączenia. Chciałbym to zrobić za pomocą oddzielnych tokenów dostępu: każdy klient otrzymuje osobny token dostępu.

Problem polega na tym, że bieżąca implementacja, której używamy (spring-security-oauth2) generuje unikalny klucz na podstawie id_klienta, nazwy użytkownika i zakresu. Zasadniczo więc, gdy otrzymujesz token dostępu, wszyscy klienci otrzymują ten sam token dostępu dla tego samego użytkownika. Odbywa się to za pomocą DefaultAuthenticationKeyGenerator.

Czy bezpiecznie jest zignorować generator kluczy uwierzytelniania i po prostu utworzyć nowy token dostępu na każde żądanie klienta?

lista kontrolna
źródło
2
czy możesz użyć zakresu do rozróżnienia każdego klienta? tj. nadaję iosowi zakres „ios”, androidowi zakres „androida”, tabletowi zakres „tabletu” itd. Ale FWIW skończyło się na napisaniu własnej implementacji TokenServices (tak naprawdę myślę, że zrobiłem to wokół opcji domyślnej), że generowałem nowy token za każdym razem.
Rob
Ogólnie jednak implementacja OAuth2 Spring Security działała dla mnie dobrze (po przejściu przez konfigurację XML), ale zarządzanie tokenem i obiektami uwierzytelniającymi było ciągłym problemem.
Rob
2
Wyszukiwanie w Google hasła „DefaultAuthenticationKeyGenerator” doprowadziło mnie do pliku .java w bibliotece Spring-security-oauth na GitHub. Ta klasa implementuje AuthenticationKeyGeneratorinterfejs. Czy możesz stworzyć własną implementację i użyć jej zamiast tego?
Greg Burghardt,
Adres URL pliku .java, który znalazłem: github.com/spring-projects/spring-security-oauth/blob/master/…
Greg Burghardt
2
Zgadzam się z @Rob, że możesz wybierać z typem urządzenia na żądanie, takim jak „android”, „ios”, „web” itp.
Vikash Rajpurohit,

Odpowiedzi:

1

Wiosenna chmura zapewnia już takie zachowanie. Po prostu dodaj różnych klientów. Podobnie jak iosAppClient, androidAppClient w twojej klasie AuthorizationServerConfiguration.

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
                clients.inMemory().withClient("androidAppclient")
                    .secret("clientsecret")
                    .autoApprove(true)
                    .accessTokenValiditySeconds(120)
                    .authorizedGrantTypes("password")
                    .resourceIds("accountservice")
                    .scopes("read", "write")
                    .and()
                    .withClient("iosappclient")
                    ........

        }

W backendie możesz uzyskać identyfikator klienta w następujący sposób

clientId = ((OAuth2Authentication) authentication).getOAuth2Request().getClientId();

i zaimplementuj różne zachowania w zależności od clientId.

Skały360
źródło
0

Jedna odpowiedź jest taka, że ​​każda platforma aplikacji jest innym klientem, więc powinien mieć inny identyfikator klienta. Jeden dla aplikacji na iOS, jeden dla strony internetowej itp.

Jeśli chodzi o rozróżnienie między powiedzmy iPadem a iPhonem, proponuję nie polegać na tym w systemie OAuth.

RibaldEddie
źródło
0

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 AuthenticationKeyGeneratorniestandardową implementacją, która zastępuje DefaultAuthenticationKeyGeneratori dodaje nowy parametr client_instance_idw 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.

Cosmin Radu
źródło