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

Posted

技术标签:

【中文标题】将使用 Google OAuth2.0 的登录电子邮件限制为特定域名【英文标题】:Restrict Login Email with Google OAuth2.0 to Specific Domain Name 【发布时间】:2012-06-07 04:45:54 【问题描述】:

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

是否有人对如何执行此操作、有关官方接受的执行方法的文档或简单、安全的解决方法有任何建议?

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

【问题讨论】:

我也在研究这个。我有一个应用程序,我希望只有在我们的商业领域的谷歌应用程序上拥有帐户的人才能访问该应用程序。 google OpenID 实现可能更适合我们俩... 如何使用google sdk和c#实现域用户登录? 请大家看看这个问题***.com/questions/34220051/… 请我在这个问题上有一个赏金,所以有人可以帮助我 【参考方案1】:

使用 Laravel Socialite 登录 Google https://laravel.com/docs/8.x/socialite#optional-parameters

use Laravel\Socialite\Facades\Socialite;

return Socialite::driver('google')
    ->with(['hd' => 'pontomais.com.br'])
    ->redirect();

【讨论】:

【参考方案2】:

自 2015 年以来,有一个 function in the library 来设置它,而无需像 aaron-bruce 在 workaround 中那样编辑库的源代码

在生成网址之前,只需针对您的 Google 客户端调用 setHostedDomain

$client->setHostedDomain("HOSTED DOMAIN")

【讨论】:

【参考方案3】:

客户端:

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

服务器端:

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

全栈示例:

网页代码:

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

【讨论】:

【参考方案4】:

这是我在 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.com 2 这样的电子邮件地址来欺骗该功能。在传统的登录系统中我可以,但这个电子邮件地址永远不会存在于谷歌中。如果不是有效的 Google 帐户,则无法登录。

【讨论】:

【参考方案5】:

在定义您的提供者时,请在末尾使用 'hd' 参数传入一个哈希值。你可以在这里阅读。 https://developers.google.com/accounts/docs/OpenIDConnect#hd-param

例如,对于 config/initializers/devise.rb

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

【讨论】:

这很容易被规避,允许访问其他域的登录。它仅适用于限制向用户显示的可用帐户。【参考方案6】:

所以我有一个答案给你。在 oauth 请求中,您可以添加“hd=domain.com”,它将限制对来自该域的用户进行身份验证(我不知道您是否可以执行多个域)。您可以找到文档中的 hd 参数here

我从这里使用 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/

【讨论】:

我不知道这个参数,你能链接到你发现它的地方吗? 不幸的是,我不得不从我的一位同事那里获得信息,我在谷歌文档中的任何地方都找不到。我的同事认为他在 OpenID 规范中找到了参考,并在 OpenAuth 规范中进行了尝试,它似乎有效。我想请谨慎使用,因为它似乎是未记录的功能。 重要提示:即使您在createAuthUrl 函数中指定了hd 参数,您仍然需要验证用户是否使用您的域电子邮件地址登录。更改链接参数以允许所有电子邮件地址并随后访问您的应用程序非常容易。 有关hd参数用法的Google文档请参阅developers.google.com/identity/work/it-apps和hd URI参数的参考可以找到developers.google.com/identity/protocols/…在概要中,应该查看hd参数作为 Google Auth 端的基于域的显示过滤器,但仍应在您端进行验证。 很好,目前在hd参数中,我只能限制一个域,现在如果我想限制两个或三个域呢?

以上是关于将使用 Google OAuth2.0 的登录电子邮件限制为特定域名的主要内容,如果未能解决你的问题,请参考以下文章

oauth2.0授予Web应用访问用户的Google spreadhseets所需的最小范围是多少?

如何使用Firebase接入Google登录?

Spring Security + Google OAuth2 登录:访问令牌为空?

使用 oAuth2.0 和表单登录的 Spring Security

OAuth 2.0 授权认证详解

可以在 oauth2 中验证电子邮件地址吗?