我似乎找不到任何关于如何限制我的网页应用程序(使用OAuth2.0和Google API)只接受来自特定域名或一组域名的用户认证请求的文档。我想要白名单而不是黑名单。
是否有人可以提出如何做到这一点的建议,官方认可方法的文档,或者一个简单,安全的解决办法?
为了记录,除非他们通过 Google 的 OAuth 认证尝试登录,否则我不知道任何有关用户的信息。我只收到基本的用户信息和电子邮件地址。
我似乎找不到任何关于如何限制我的网页应用程序(使用OAuth2.0和Google API)只接受来自特定域名或一组域名的用户认证请求的文档。我想要白名单而不是黑名单。
是否有人可以提出如何做到这一点的建议,官方认可方法的文档,或者一个简单,安全的解决办法?
为了记录,除非他们通过 Google 的 OAuth 认证尝试登录,否则我不知道任何有关用户的信息。我只收到基本的用户信息和电子邮件地址。
我为你准备了一个答案。在OAuth请求中,你可以添加 hd=example.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=example.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/
createAuthUrl
函数中指定了hd
参数,但仍需要验证用户是否使用您的域名电子邮件地址登录。很容易更改链接参数以允许所有电子邮件地址,并随后获得对您的应用程序的访问权限。 - VictorKilohd
参数用法的Google文档,请参见https://developers.google.com/identity/work/it-apps,`hd` URI参数的参考资料可在https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters找到。简而言之,`hd`参数应被视为基于域的显示过滤器,用于Google身份验证方面,但仍应在您的方面进行验证。 - Will B.使用auth2
初始化函数,您可以传递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.example'
});
// 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(); });
});
}
});
});
如果你不使用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.example';
return tokenIsOK ? resolve() : reject();
});
});
};
config.omniauth :google_oauth2, 'identifier', 'key', {hd: 'yourdomain.com'}
//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中永远不存在。如果它不是有效的Google帐户,则无法登录。
使用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();