Token di accesso multipli Oauth2


13

Ho un'API che utilizza oAuth2 e le mie app mobili che usano questa API come backend. Poiché gli utenti possono accedere contemporaneamente tramite più dispositivi (ad es. IPhone, iPad, tablet Android o telefono Android), ho bisogno dell'API per distinguere tra ciascuna connessione. Vorrei farlo tramite token di accesso separati: ogni client riceve un token di accesso separato.

Il problema è che l'attuale implementazione che utilizziamo (spring-security-oauth2) genera una chiave univoca basata su client_id, nome utente e ambito. Quindi, in pratica, quando si ottiene un token di accesso, tutti i client ottengono lo stesso token di accesso per lo stesso utente. Questo viene fatto usando DefaultAuthenticationKeyGenerator.

È sicuro ignorare il generatore di chiavi di autenticazione e creare semplicemente un nuovo token di accesso su ogni richiesta da un client?


2
puoi usare l'ambito per differenziare ogni cliente? cioè dare a iOS un ambito "ios", android un ambito "android", il tablet un ambito "tablet", ecc. Ma FWIW ho finito per scrivere la mia implementazione TokenServices (in realtà penso di averlo reso un involucro attorno all'impostazione predefinita) che generato ogni volta un nuovo token.
Rob,

In generale, tuttavia, l'implementazione di OAuth2 di Spring Security ha funzionato bene per me (una volta ottenuta la configurazione XML), ma la gestione del token e degli oggetti di autenticazione era un punto problematico in corso.
Rob,

2
La ricerca di "DefaultAuthenticationKeyGenerator" mi ha portato a un file .java nella libreria spring-security-oauth su GitHub. Quella classe implementa l' AuthenticationKeyGeneratorinterfaccia. Potresti creare la tua implementazione e usarla invece?
Greg Burghardt,


2
Sono d'accordo con @Rob, puoi richiedere devicetype su richiesta come "android", "ios", "web" ecc.
Vikash Rajpurohit,

Risposte:


1

Spring cloud offre già questo comportamento. Aggiungi solo diversi clienti. Come iosAppClient, androidAppClient nella tua classe 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")
                    ........

        }

Nel backend è possibile ottenere il clientID come il seguente

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

e implementare comportamenti diversi in base al clientId.


0

Una risposta è che ogni piattaforma di app è un client diverso, quindi dovrebbe avere un ID client diverso. Uno per l'app iOS, uno per il sito Web, ecc.

Per quanto riguarda la differenziazione tra diciamo un iPad rispetto a un iPhone, suggerirei di non fare affidamento sul sistema OAuth per questo.


0

Mi sono imbattuto nello stesso problema durante lo sviluppo del mio backend con Spring Boot e OAuth2. Il problema che ho riscontrato è che, se più dispositivi condividessero gli stessi token, una volta che un dispositivo avesse aggiornato il token, l'altro dispositivo sarebbe stato all'oscuro e, per farla breve, entrambi i dispositivi sarebbero entrati in una frenesia di aggiornamento del token. La mia soluzione è stata quella di sostituire il valore predefinito AuthenticationKeyGeneratorcon un'implementazione personalizzata che sovrascrive DefaultAuthenticationKeyGeneratore aggiunge un nuovo parametro client_instance_idnella combinazione del generatore di chiavi. I miei client mobili invierebbero quindi questo parametro che deve essere univoco tra le installazioni di app (iOS o Android). Questo non è un requisito speciale, poiché la maggior parte delle app mobili tiene già traccia dell'istanza dell'applicazione in qualche modo.

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);
    }

}

che poi inietteresti in modo simile:

final JdbcTokenStore tokenStore = new JdbcTokenStore(mDataSource);
tokenStore.setAuthenticationKeyGenerator(new EnhancedAuthenticationKeyGenerator());

La richiesta HTTP sarebbe quindi simile a questa

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}}

Il vantaggio di utilizzare questo approccio è che, se il client non invia un client_instance_id, verrebbe generata la chiave predefinita e se viene fornita un'istanza, la stessa chiave viene restituita ogni volta per la stessa istanza. Inoltre, la chiave è indipendente dalla piattaforma. Il rovescio della medaglia sarebbe che il digest MD5 (usato internamente) viene chiamato due volte.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.