使用googleauth gem在Rails 7 API中验证Google OAuth2访问令牌
解决Rails 7 API验证Google令牌的签名错误问题
首先你混淆了Google的访问令牌(access_token)和ID令牌(id_token):googleauth gem的IDTokens::Verifier专门用于验证ID令牌,而非访问令牌。前端应该传递Google登录返回的id_token,而非access_token。如果必须使用访问令牌,需要调用Google的tokeninfo端点,但更推荐用ID令牌做后端验证。
另外你的代码缺少关键的**受众(Audience)**参数——这是ID令牌验证的必填项,必须严格匹配你在Google Cloud Console中创建的OAuth客户端ID,否则必然触发验证失败。
以下是修正后的验证代码:
def validate_access_token # 提取令牌(前端需传递id_token而非access_token) token = request.headers['Authorization']&.gsub(/bearer /i, '') return render json: { error: 'Missing token' }, status: :unauthorized unless token # 替换为你的Google OAuth客户端ID(从Google Cloud Console获取) client_id = 'your-google-oauth-client-id.apps.googleusercontent.com' # Verifier会自动使用默认的Google证书源,无需手动指定key_source verifier = Google::Auth::IDTokens::Verifier.new(audience: client_id) begin # 验证令牌并返回解码后的用户信息payload payload = verifier.verify(token) # 可从payload中提取用户唯一标识sub、邮箱等信息,用于关联系统用户 # current_user = User.find_by(google_id: payload['sub']) rescue Google::Auth::IDTokens::VerificationError => e case e when Google::Auth::IDTokens::ExpiredTokenError render json: { error: 'Token expired' }, status: :unauthorized when Google::Auth::IDTokens::InvalidAudienceError render json: { error: 'Invalid audience' }, status: :unauthorized else render json: { error: "Token verification failed: #{e.message}" }, status: :unauthorized end end end
关键注意事项:
- 令牌类型:前端需传递Google登录回调中的
id_token(比如使用@react-oauth/google库时,response.credential字段就是id_token),不要传access_token。 - 受众匹配:
audience参数必须与Google Cloud Console中创建的OAuth客户端ID完全一致,大小写、字符都不能错。 - 密钥源:
Verifier默认会使用https://www.googleapis.com/oauth2/v3/certs作为证书源,原代码中手动指定这部分是多余且正确的,但无需保留。
若必须验证访问令牌:
如果业务需求只能用access_token,不要用googleauth gem,直接调用Google的tokeninfo端点验证:
def validate_access_token access_token = request.headers['Authorization']&.gsub(/bearer /i, '') return render json: { error: 'Missing token' }, status: :unauthorized unless access_token response = Faraday.get("https://oauth2.googleapis.com/tokeninfo", { access_token: access_token }) if response.status != 200 render json: { error: 'Invalid access token' }, status: :unauthorized else payload = JSON.parse(response.body) # 必须验证返回的aud字段是否匹配你的客户端ID unless payload['aud'] == 'your-google-oauth-client-id.apps.googleusercontent.com' render json: { error: 'Invalid audience' }, status: :unauthorized end end end
这种方式需要额外的HTTP请求,验证效率不如ID令牌高。
内容的提问来源于stack exchange,提问作者Dana Scheider
相关产品推荐
相关产品推荐

