Plusieurs jetons d'accès Oauth2

13

J'ai une API qui utilise oAuth2 et mes propres applications mobiles qui utilisent cette API comme backend. Étant donné que les utilisateurs peuvent être connectés via plusieurs appareils (c'est-à-dire iPhone, iPad, tablette Android ou téléphone Android) en même temps, j'ai besoin de l'API pour faire la distinction entre chaque connexion. Je voudrais le faire via des jetons d'accès séparés: chaque client obtient un jeton d'accès distinct.

Le problème est que l'implémentation actuelle que nous utilisons (spring-security-oauth2) génère une clé unique basée sur client_id, username et scope. Donc, fondamentalement, lors de l'obtention d'un jeton d'accès, tous les clients obtiennent le même jeton d'accès pour le même utilisateur. Cela se fait à l'aide de DefaultAuthenticationKeyGenerator.

Est-il sûr d'ignorer le générateur de clé d'authentification et de simplement créer un nouveau jeton d'accès à chaque demande d'un client?

liste de contrôle
la source
2
pouvez-vous utiliser la portée pour différencier chaque client? c'est-à-dire donner à ios une portée "ios", android une portée "android", la tablette une portée "tablette", etc. généré un nouveau jeton à chaque fois.
Rob
En général, cependant, l'implémentation de Spring Security OAuth2 a bien fonctionné pour moi (une fois que j'ai terminé la configuration XML), mais la gestion du jeton et des objets d'authentification était un problème permanent.
Rob
2
La recherche de "DefaultAuthenticationKeyGenerator" sur Google m'a conduit à un fichier .java dans la bibliothèque spring-security-oauth sur GitHub. Cette classe implémente l' AuthenticationKeyGeneratorinterface. Pourriez-vous créer votre propre implémentation et l'utiliser à la place?
Greg Burghardt
L'URL du fichier .java que j'ai trouvée: github.com/spring-projects/spring-security-oauth/blob/master/…
Greg Burghardt
2
Je suis d'accord avec @Rob, vous pouvez utiliser devicetype dans une demande comme "android", "ios", "web" etc.
Vikash Rajpurohit

Réponses:

1

Le nuage de printemps fournit déjà ce comportement. Ajoutez simplement différents clients. Comme iosAppClient, androidAppClient dans votre 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")
                    ........

        }

Dans le backend, vous pouvez obtenir l'ID client comme suit

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

et implémenter un comportement différent basé sur le clientId.

Rocks360
la source
0

Une réponse est que chaque plate-forme d'application est un client différent, donc devrait avoir un identifiant client différent. Un pour l'application iOS, un pour le site Web, etc.

En ce qui concerne la distinction entre, disons, un iPad et un iPhone, je suggérerais de ne pas compter sur le système OAuth pour cela.

RibaldEddie
la source
0

Je suis tombé sur le même problème lors du développement de mon backend avec Spring Boot et OAuth2. Le problème que j'ai rencontré était que, si plusieurs appareils partageaient les mêmes jetons, une fois qu'un appareil actualisait le jeton, l'autre appareil était sans aucune idée et, pour faire court, les deux appareils entraient dans une frénésie de rafraîchissement de jeton. Ma solution était de remplacer la valeur AuthenticationKeyGeneratorpar défaut par une implémentation personnalisée qui remplaceDefaultAuthenticationKeyGenerator et ajoute un nouveau paramètre client_instance_iddans le mélange de générateurs de clés. Mes clients mobiles enverraient alors ce paramètre qui doit être unique dans toutes les installations d'applications (iOS ou Android). Ce n'est pas une exigence particulière, car la plupart des applications mobiles suivent déjà l'instance d'application sous une forme ou une autre.

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

}

que vous injecteriez ensuite de manière similaire:

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

La requête HTTP ressemblerait alors à quelque chose comme ceci

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

L'avantage de l'utilisation de cette approche est que, si le client n'envoie pas de client_instance_id, la clé par défaut est générée et si une instance est fournie, la même clé est renvoyée à chaque fois pour la même instance. En outre, la clé est indépendante de la plate-forme. L'inconvénient serait que le condensé MD5 (utilisé en interne) est appelé deux fois.

Cosmin Radu
la source