95 votes

Restreindre l'e-mail de connexion avec Google OAuth2.0 à un nom de domaine spécifique

Je n'arrive pas à trouver de documentation sur la façon de restreindre la connexion à mon application Web (qui utilise OAuth2.0 et les API de Google) pour n'accepter que les demandes d'authentification des utilisateurs ayant une adresse électronique sur un nom de domaine spécifique ou un ensemble de noms de domaine. Je voudrais établir une liste blanche plutôt qu'une liste noire.

Quelqu'un a-t-il des suggestions sur la manière de procéder, de la documentation sur la méthode officiellement acceptée ou une solution de contournement facile et sûre ?

Pour mémoire, je ne connais aucune information sur l'utilisateur avant qu'il ne tente de se connecter via l'authentification OAuth de Google. Tout ce que je reçois en retour, ce sont les informations de base sur l'utilisateur et son adresse électronique.

43voto

Aaron Bruce Points 807

Alors j'ai une réponse pour vous. Dans la requête oauth, vous pouvez ajouter "hd=domaine.com" et cela limitera l'authentification aux utilisateurs de ce domaine (je ne sais pas si vous pouvez faire plusieurs domaines). Vous pouvez trouver le paramètre hd documenté aquí

J'utilise les bibliothèques de l'API de Google à partir d'ici : http://code.google.com/p/google-api-php-client/wiki/OAuth2 J'ai donc dû modifier manuellement le fichier /auth/apiOAuth2.php comme ceci :

public function createAuthUrl($scope) {
    $params = array(
        'response_type=code',
        'redirect_uri=' . urlencode($this->redirectUri),
        'client_id=' . urlencode($this->clientId),
        'scope=' . urlencode($scope),
        'access_type=' . urlencode($this->accessType),
        'approval_prompt=' . urlencode($this->approvalPrompt),
        'hd=domain.com'
    );

    if (isset($this->state)) {
        $params[] = 'state=' . urlencode($this->state);
    }
    $params = implode('&', $params);
    return self::OAUTH2_AUTH_URL . "?$params";
}

Edit : Je travaille toujours sur cette application et j'ai trouvé ceci, qui est peut-être la réponse la plus correcte à cette question. https://developers.google.com/google-apps/profiles/

13voto

Jordon Biondo Points 3765

Côté client :

Utilisation de la auth2 vous pouvez passer la fonction hosted_domain pour restreindre les comptes listés dans la fenêtre popup de connexion à ceux qui correspondent à vos critères de sélection. hosted_domain . Vous pouvez voir cela dans la documentation ici : https://developers.google.com/identity/sign-in/web/reference

Côté serveur :

Même avec une liste restreinte côté client, vous devrez vérifier que le fichier id_token correspond au domaine hébergé que vous avez spécifié. Pour certaines implémentations, cela signifie vérifier la valeur hd que vous recevez de Google après avoir vérifié le jeton.

Full Stack Exemple :

Code Web :

gapi.load('auth2', function () {
    // init auth2 with your hosted_domain
    // only matching accounts will show up in the list or be accepted
    var auth2 = gapi.auth2.init({
        client_id: "your-client-id.apps.googleusercontent.com",
        hosted_domain: 'your-special-domain.com'
    });

    // setup your signin button
    auth2.attachClickHandler(yourButtonElement, {});

    // when the current user changes
    auth2.currentUser.listen(function (user) {
        // if the user is signed in
        if (user && user.isSignedIn()) {
            // validate the token on your server,
            // your server will need to double check that the
            // `hd` matches your specified `hosted_domain`;
            validateTokenOnYourServer(user.getAuthResponse().id_token)
                .then(function () {
                    console.log('yay');
                })
                .catch(function (err) {
                    auth2.then(function() { auth2.signOut(); });
                });
        }
    });
});

Code du serveur (en utilisant la bibliothèque Node.js de Google) :

Si vous n'utilisez pas Node.js, vous pouvez voir d'autres exemples ici : https://developers.google.com/identity/sign-in/web/backend-auth

const GoogleAuth = require('google-auth-library');
const Auth = new GoogleAuth();
const authData = JSON.parse(fs.readFileSync(your_auth_creds_json_file));
const oauth = new Auth.OAuth2(authData.web.client_id, authData.web.client_secret);

const acceptableISSs = new Set(
    ['accounts.google.com', 'https://accounts.google.com']
);

const validateToken = (token) => {
    return new Promise((resolve, reject) => {
        if (!token) {
            reject();
        }
        oauth.verifyIdToken(token, null, (err, ticket) => {
            if (err) {
                return reject(err);
            }
            const payload = ticket.getPayload();
            const tokenIsOK = payload &&
                  payload.aud === authData.web.client_id &&
                  new Date(payload.exp * 1000) > new Date() &&
                  acceptableISSs.has(payload.iss) &&
                  payload.hd === 'your-special-domain.com';
            return tokenIsOK ? resolve() : reject();
        });
    });
};

9voto

Kosmonaut Points 380

Lorsque vous définissez votre fournisseur, passez un hash à la fin avec le paramètre 'hd'. Vous pouvez lire ce qui suit ici. https://developers.google.com/accounts/docs/OpenIDConnect#hd-param

Par exemple, pour config/initializers/devise.rb

config.omniauth :google_oauth2, 'identifier', 'key', {hd: 'yourdomain.com'}

2voto

mjoyce91 Points 306

Voici ce que j'ai fait en utilisant le passeport dans node.js. profile est l'utilisateur qui tente de se connecter.

//passed, stringified email login
var emailString = String(profile.emails[0].value);
//the domain you want to whitelist
var yourDomain = '@google.com';
//check the x amount of characters including and after @ symbol of passed user login.
//This means '@google.com' must be the final set of characters in the attempted login 
var domain = emailString.substr(emailString.length - yourDomain.length);

//I send the user back to the login screen if domain does not match 
if (domain != yourDomain)
   return done(err);

Il suffit ensuite de créer une logique pour rechercher plusieurs domaines au lieu d'un seul. Je pense que cette méthode est sûre car 1. le symbole '@' n'est pas un caractère valide dans la première ou la deuxième partie d'une adresse électronique. Je n'ai pas pu tromper la fonction en créant une adresse électronique du type mike@fake@google.com 2. Dans un système de connexion traditionnel, je pourrais, mais cette adresse électronique ne pourrait jamais exister dans Google. S'il ne s'agit pas d'un compte Google valide, vous ne pouvez pas vous connecter.

2voto

JBithell Points 617

Depuis 2015, il y a eu un fonction dans la bibliothèque pour définir ce paramètre sans avoir besoin de modifier le code source de la bibliothèque comme dans le fichier solution de contournement par aaron-bruce

Avant de générer l'url, il suffit d'appeler setHostedDomain contre votre client Google

$client->setHostedDomain("HOSTED DOMAIN")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X