Node环境下Actions-on-Google结合Auth0账号关联如何获取认证提供商
Shaun,我明白你赶项目的焦虑——这个问题确实有点坑,因为Actions on Google V2的SignIn意图返回的对象里确实不会直接携带用户选择的认证提供商信息,但咱们可以从Auth0的配置和后续API调用入手解决,步骤其实很清晰:
核心思路
Actions on Google的SignIn只负责完成认证流程并返回Token,而用户的登录提供商信息需要从Auth0那边获取——我们可以通过Auth0的规则把提供商信息注入到Token或用户信息接口中,再在你的Node.js应用里提取出来。
步骤1:在Auth0中添加规则,注入提供商信息
登录Auth0控制台,进入Rules页面,点击「Create Rule」新建一个规则,选择「Empty Rule」模板,替换成以下代码:
function addProviderToUserInfo(user, context, callback) { // 把提供商信息添加到userinfo响应和ID Token的自定义声明中 context.idToken['https://your-custom-namespace.com/provider'] = user.provider; context.accessToken['https://your-custom-namespace.com/provider'] = user.provider; // 同时确保provider字段出现在userinfo的返回结果里 context.userInfo.provider = user.provider; callback(null, user, context); }
注意:https://your-custom-namespace.com/provider是自定义声明的命名空间,必须是合法的URL格式(可以用你自己的域名或者项目相关的URL),目的是避免和OpenID标准声明冲突。
步骤2:在你的Node.js应用中获取提供商信息
你已经拿到了Access Token,接下来可以通过两种方式获取带提供商信息的用户数据:
方式一:调用Auth0的UserInfo接口(推荐)
用你喜欢的HTTP库(比如axios)调用Auth0的/userinfo端点,这个接口会直接返回包含provider字段的用户档案:
const axios = require('axios'); async function handleSignInConfirmation(conv, params, signin) { if (signin.status === 'OK') { const accessToken = conv.user.access.token; const auth0Domain = '你的Auth0域名(比如xxx.auth0.com)'; try { const response = await axios.get(`https://${auth0Domain}/userinfo`, { headers: { Authorization: `Bearer ${accessToken}` } }); // 获取关键信息 const userProvider = response.data.provider; // 比如返回'google-oauth2'、'facebook'、'twitter' const userName = response.data.name; const userEmail = response.data.email; // 接下来就可以根据provider做对应的逻辑处理了 conv.ask(`欢迎回来${userName}!你使用${userProvider}完成了登录~`); } catch (err) { console.error('获取用户信息失败:', err); conv.ask('抱歉,暂时无法获取你的账户信息,请稍后重试。'); } } else { conv.ask('登录未完成,请重试哦。'); } }
方式二:解码ID Token获取提供商信息
如果你已经拿到了ID Token(因为你请求了OPENID权限,所以conv.user.idToken应该能拿到),可以用jsonwebtoken库解码并提取自定义声明:
const jwt = require('jsonwebtoken'); const jwksClient = require('jwks-rsa'); // 用来获取Auth0的公钥,确保Token验证安全 async function getProviderFromIDToken(idToken, auth0Domain, clientId) { // 初始化JWKS客户端获取公钥 const client = jwksClient({ jwksUri: `https://${auth0Domain}/.well-known/jwks.json` }); function getKey(header, callback) { client.getSigningKey(header.kid, function(err, key) { const signingKey = key.getPublicKey(); callback(null, signingKey); }); } // 验证并解码Token(一定要验证,防止伪造) return new Promise((resolve, reject) => { jwt.verify(idToken, getKey, { audience: clientId, issuer: `https://${auth0Domain}/` }, (err, decoded) => { if (err) reject(err); // 提取自定义声明里的提供商信息 const provider = decoded['https://your-custom-namespace.com/provider']; resolve(provider); }); }); } // 在意图处理器中调用 async function handleSignInConfirmation(conv, params, signin) { if (signin.status === 'OK') { const idToken = conv.user.idToken; const auth0Domain = '你的Auth0域名'; const clientId = '你的Auth0客户端ID'; try { const userProvider = await getProviderFromIDToken(idToken, auth0Domain, clientId); // 后续逻辑... } catch (err) { console.error('解码Token失败:', err); // 错误处理... } } }
额外检查
确保你的Auth0应用配置正确:
- 在Connections里已经启用了Google、Facebook、Twitter
- 在Applications -> 你的应用 -> Settings中,
Allowed Callback URLs已经添加了Actions on Google的回调地址:https://oauth-redirect.googleusercontent.com/r/你的项目ID
这样就能顺利拿到用户选择的认证提供商,进而正确处理用户档案信息了,祝项目顺利上线!
内容的提问来源于stack exchange,提问作者Shaun Heveron

