将带有Google OAuth2.0的登录电子邮件限制为特定域名


90

我似乎找不到任何有关如何限制登录到我的Web应用程序(使用OAuth2.0和Google API)的文档,以仅接受来自具有特定域名或一组域名的电子邮件的用户的身份验证请求的文档。我想将清单列入黑名单,而不是列入黑名单。

是否有人对如何执行此操作有任何建议,关于这样做的官方认可方法的文档,或者是否可以轻松,安全地解决?

作为记录,在用户尝试通过Google的OAuth身份验证登录之前,我不知道有关该用户的任何信息。我所收到的只是基本的用户信息和电子邮件。


3
我也在对此进行研究。我有一个应用程序,只有那些在我们用于企业域的Google应用程序中拥有帐户的人才能访问。Google OpenID实现可能更适合我们俩……
Aaron Bruce

1
如何使用Google SDK和C#实现域用户登录?
user1021583

1
可以请一些一看这个问题stackoverflow.com/questions/34220051/...

1
请问我对这个问题有丰富的赏金,所以有人可以帮我

Answers:


42

因此,我为您找到了答案。在oauth请求中,您可以添加“ hd = domain.com”,它将限制对来自该域的用户的身份验证(我不知道您是否可以做多个域)。您可以在此处找到记录的hd参数

我正在从此处使用google api库:http : //code.google.com/p/google-api-php-client/wiki/OAuth2,因此我必须手动将/auth/apiOAuth2.php文件编辑为此:

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

编辑:我仍在使用此应用程序并找到了它,这可能是对此问题的更正确答案。https://developers.google.com/google-apps/profiles/


我不知道此参数,您可以链接到找到它的地方吗?
杰森·霍尔

不幸的是,我不得不从我的一位同事那里获得信息,但我在Google文档中的任何地方都找不到。我的同事认为他在OpenID规范中找到了引用,并在OpenAuth规范中在此处进行了尝试,并且似乎可行。我想谨慎使用,因为它似乎是未记录的功能。
亚伦·布鲁斯

31
重要说明:即使您hdcreateAuthUrl函数中指定了参数,您仍然需要验证用户是否使用您的域电子邮件地址登录。更改链接参数以允许所有电子邮件地址并随后访问您的应用程序非常容易。
VictorKilo

1
有关谷歌的文档hd参数的用法见developers.google.com/identity/work/it-apps而的参考hdURI参数可以发现developers.google.com/identity/protocols/...在简介,hdPARAM应在Google Auth端被视为基于域的显示过滤器,但仍应在您这一端进行验证。
fyrye 2016年

2
太好了,目前在hd参数中,我只能限制一个域,如果要限制两个或三个域怎么办?
Jay Patel '18

11

客户端:

使用auth2init函数,您可以传递hosted_domain参数以将登录弹出窗口中列出的帐户限制为与您的帐户匹配的帐户hosted_domain。您可以在以下文档中看到此内容:https : //developers.google.com/identity/sign-in/web/reference

服务器端:

即使具有受限的客户端列表,您也需要验证id_token与指定的托管域匹配。对于某些实现,这意味着hd在验证令牌后检查从google获得的属性。

全栈示例:

网页代码:

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

服务器代码(使用googles Node.js库):

如果您不使用Node.js,则可以在此处查看其他示例: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();
        });
    });
};


2

这是我在node.js中使用通行证所做的。profile是用户尝试登录。

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

然后,只需创建逻辑即可查找多个域而不是一个域。我相信此方法是安全的,因为1.电子邮件地址的第一部分或第二部分中的'@'符号不是有效字符。我无法通过创建类似mike@fake@google.com2 的电子邮件地址来欺骗该功能。在传统的登录系统中,我可以这样做,但是该电子邮件地址在Google中永远不会存在。如果这不是有效的Google帐户,则无法登录。


1

自2015年以来,库中已有一个函数来设置此函数,而无需像aaron-bruce 的解决方法那样编辑库的源代码

在生成网址之前,只需致电setHostedDomain您的Google客户

$client->setHostedDomain("HOSTED DOMAIN")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.