Swift 使用Firebase ID令牌对GCP HTTP云函数进行身份验证不会';不行?

Swift 使用Firebase ID令牌对GCP HTTP云函数进行身份验证不会';不行?,swift,firebase,google-cloud-platform,google-cloud-functions,jwt,Swift,Firebase,Google Cloud Platform,Google Cloud Functions,Jwt,我知道这是一个重复的问题,但我还没有看到有人提出swift和python实现。此外,我尝试了其他问题中列出的所有问题,但似乎没有任何效果 环境和条件: guard let user = Auth.auth(app: authAppToUse).currentUser else { fatalError("SearchMySQL -> user: \(String(describing: Auth.auth(app: authAppToUse).currentUser))"

我知道这是一个重复的问题,但我还没有看到有人提出swift和python实现。此外,我尝试了其他问题中列出的所有问题,但似乎没有任何效果

环境和条件:

guard let user = Auth.auth(app: authAppToUse).currentUser else { fatalError("SearchMySQL -> user: \(String(describing: Auth.auth(app: authAppToUse).currentUser))") }
user.getIDTokenForcingRefresh(true) { (idToken, err) in
    if err != nil{
        fatalError("SearchMySQL -> user.getIDToken -> err: \(String(describing: err))")
    }

    guard let guardedIdToken = idToken else { fatalError("SearchMySQL -> guardedIdToken: \(String(describing: idToken))") }
    let rawJSON = [
        "data" : [
            "table": table,
            "search_by": searchBy,
            "search_by_value": searchByValue
        ]
    ]

    guard let guardedJSON = try? JSONSerialization.data(withJSONObject: rawJSON, options: .prettyPrinted) else {
        return
    }

    guard let url = URL(string: "https://us-east1-fresh-customer-dev-ocean.cloudfunctions.net/mysql_search") else { return }
    var request = URLRequest(url: url)
    request.addValue("Bearer \(idToken)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    request.httpBody = guardedJSON

    let task = URLSession.shared.dataTask(with: request) { (data, response, err) in
        if err != nil {
            print(err?.localizedDescription)
            fatalError("SearchMySQL -> URLSession.shared.dataTask -> err: \(String(describing: err))")
        }
        guard let guardedData = data else {
              return
        }

        print(idToken)
        print(response.debugDescription)

        let json = try? JSONSerialization.jsonObject(with: guardedData, options: .allowFragments)
        print(json)

        completion(data)
    }
    task.resume()
}
def main(request):
    """Background Http Triggered Cloud Function for ********.
    Validates authentication with Firebase ID token

    Returns:
        ********.main(payload): http response code and data payload (or message)
    """

    # validate request authorization
    if not request.headers.get('Authorization'):
        log.fatal('No Authorization Token provided')
        return {'message': 'No Authorization Token provided'}, 400
    try:
        id_token = request.headers.get('Authorization')
        auth.verify_id_token(id_token)
    except (ValueError, InvalidIdTokenError, ExpiredIdTokenError, RevokedIdTokenError, CertificateFetchError) as e:
        log.fatal(f'Authorization `id_token` error: {e}')
        return {'message':f'Authorization `id_token` error: {e}'}, 400

    data_payload = request.get_json(force=True)

    if not data_payload.table:
        log.fatal('Payload missing table field.')
        return {'message': 'Payload missing table field'}, 422

    if not data_payload.search_by:
        log.fatal('Payload missing search_by field.')
        return {'message': 'Payload missing search_by field'}, 422
    
    return ********.main(data_payload)
  • 获取ID后从iOS应用程序调用http云函数 令牌(带有ID令牌)
  • 用Swift书写
  • Cloud函数是用Python编写的
  • 我不能使用HTTP callables,因为它们不能通过现有的terraform基础设施进行部署(至少我不知道,但我愿意接受任何想法)
问题:

guard let user = Auth.auth(app: authAppToUse).currentUser else { fatalError("SearchMySQL -> user: \(String(describing: Auth.auth(app: authAppToUse).currentUser))") }
user.getIDTokenForcingRefresh(true) { (idToken, err) in
    if err != nil{
        fatalError("SearchMySQL -> user.getIDToken -> err: \(String(describing: err))")
    }

    guard let guardedIdToken = idToken else { fatalError("SearchMySQL -> guardedIdToken: \(String(describing: idToken))") }
    let rawJSON = [
        "data" : [
            "table": table,
            "search_by": searchBy,
            "search_by_value": searchByValue
        ]
    ]

    guard let guardedJSON = try? JSONSerialization.data(withJSONObject: rawJSON, options: .prettyPrinted) else {
        return
    }

    guard let url = URL(string: "https://us-east1-fresh-customer-dev-ocean.cloudfunctions.net/mysql_search") else { return }
    var request = URLRequest(url: url)
    request.addValue("Bearer \(idToken)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    request.httpBody = guardedJSON

    let task = URLSession.shared.dataTask(with: request) { (data, response, err) in
        if err != nil {
            print(err?.localizedDescription)
            fatalError("SearchMySQL -> URLSession.shared.dataTask -> err: \(String(describing: err))")
        }
        guard let guardedData = data else {
              return
        }

        print(idToken)
        print(response.debugDescription)

        let json = try? JSONSerialization.jsonObject(with: guardedData, options: .allowFragments)
        print(json)

        completion(data)
    }
    task.resume()
}
def main(request):
    """Background Http Triggered Cloud Function for ********.
    Validates authentication with Firebase ID token

    Returns:
        ********.main(payload): http response code and data payload (or message)
    """

    # validate request authorization
    if not request.headers.get('Authorization'):
        log.fatal('No Authorization Token provided')
        return {'message': 'No Authorization Token provided'}, 400
    try:
        id_token = request.headers.get('Authorization')
        auth.verify_id_token(id_token)
    except (ValueError, InvalidIdTokenError, ExpiredIdTokenError, RevokedIdTokenError, CertificateFetchError) as e:
        log.fatal(f'Authorization `id_token` error: {e}')
        return {'message':f'Authorization `id_token` error: {e}'}, 400

    data_payload = request.get_json(force=True)

    if not data_payload.table:
        log.fatal('Payload missing table field.')
        return {'message': 'Payload missing table field'}, 422

    if not data_payload.search_by:
        log.fatal('Payload missing search_by field.')
        return {'message': 'Payload missing search_by field'}, 422
    
    return ********.main(data_payload)
因此,我假设在授权头中包含Firebase用户的Firebase ID令牌是可行的,但即使强制刷新也不适用于我。我收到一个403状态响应,消息为:
无法验证访问令牌
。也就是说,如果我进入CLI并通过:
gcloud auth print identity token
获取我的实际gcp用户帐户的id令牌,然后用所述令牌替换头部,我将被验证

Swift请求代码(请原谅缺少约定,这只是在我真正实现之前进行的POCing):

guard let user = Auth.auth(app: authAppToUse).currentUser else { fatalError("SearchMySQL -> user: \(String(describing: Auth.auth(app: authAppToUse).currentUser))") }
user.getIDTokenForcingRefresh(true) { (idToken, err) in
    if err != nil{
        fatalError("SearchMySQL -> user.getIDToken -> err: \(String(describing: err))")
    }

    guard let guardedIdToken = idToken else { fatalError("SearchMySQL -> guardedIdToken: \(String(describing: idToken))") }
    let rawJSON = [
        "data" : [
            "table": table,
            "search_by": searchBy,
            "search_by_value": searchByValue
        ]
    ]

    guard let guardedJSON = try? JSONSerialization.data(withJSONObject: rawJSON, options: .prettyPrinted) else {
        return
    }

    guard let url = URL(string: "https://us-east1-fresh-customer-dev-ocean.cloudfunctions.net/mysql_search") else { return }
    var request = URLRequest(url: url)
    request.addValue("Bearer \(idToken)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    request.httpBody = guardedJSON

    let task = URLSession.shared.dataTask(with: request) { (data, response, err) in
        if err != nil {
            print(err?.localizedDescription)
            fatalError("SearchMySQL -> URLSession.shared.dataTask -> err: \(String(describing: err))")
        }
        guard let guardedData = data else {
              return
        }

        print(idToken)
        print(response.debugDescription)

        let json = try? JSONSerialization.jsonObject(with: guardedData, options: .allowFragments)
        print(json)

        completion(data)
    }
    task.resume()
}
def main(request):
    """Background Http Triggered Cloud Function for ********.
    Validates authentication with Firebase ID token

    Returns:
        ********.main(payload): http response code and data payload (or message)
    """

    # validate request authorization
    if not request.headers.get('Authorization'):
        log.fatal('No Authorization Token provided')
        return {'message': 'No Authorization Token provided'}, 400
    try:
        id_token = request.headers.get('Authorization')
        auth.verify_id_token(id_token)
    except (ValueError, InvalidIdTokenError, ExpiredIdTokenError, RevokedIdTokenError, CertificateFetchError) as e:
        log.fatal(f'Authorization `id_token` error: {e}')
        return {'message':f'Authorization `id_token` error: {e}'}, 400

    data_payload = request.get_json(force=True)

    if not data_payload.table:
        log.fatal('Payload missing table field.')
        return {'message': 'Payload missing table field'}, 422

    if not data_payload.search_by:
        log.fatal('Payload missing search_by field.')
        return {'message': 'Payload missing search_by field'}, 422
    
    return ********.main(data_payload)
Python云函数:

guard let user = Auth.auth(app: authAppToUse).currentUser else { fatalError("SearchMySQL -> user: \(String(describing: Auth.auth(app: authAppToUse).currentUser))") }
user.getIDTokenForcingRefresh(true) { (idToken, err) in
    if err != nil{
        fatalError("SearchMySQL -> user.getIDToken -> err: \(String(describing: err))")
    }

    guard let guardedIdToken = idToken else { fatalError("SearchMySQL -> guardedIdToken: \(String(describing: idToken))") }
    let rawJSON = [
        "data" : [
            "table": table,
            "search_by": searchBy,
            "search_by_value": searchByValue
        ]
    ]

    guard let guardedJSON = try? JSONSerialization.data(withJSONObject: rawJSON, options: .prettyPrinted) else {
        return
    }

    guard let url = URL(string: "https://us-east1-fresh-customer-dev-ocean.cloudfunctions.net/mysql_search") else { return }
    var request = URLRequest(url: url)
    request.addValue("Bearer \(idToken)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    request.httpBody = guardedJSON

    let task = URLSession.shared.dataTask(with: request) { (data, response, err) in
        if err != nil {
            print(err?.localizedDescription)
            fatalError("SearchMySQL -> URLSession.shared.dataTask -> err: \(String(describing: err))")
        }
        guard let guardedData = data else {
              return
        }

        print(idToken)
        print(response.debugDescription)

        let json = try? JSONSerialization.jsonObject(with: guardedData, options: .allowFragments)
        print(json)

        completion(data)
    }
    task.resume()
}
def main(request):
    """Background Http Triggered Cloud Function for ********.
    Validates authentication with Firebase ID token

    Returns:
        ********.main(payload): http response code and data payload (or message)
    """

    # validate request authorization
    if not request.headers.get('Authorization'):
        log.fatal('No Authorization Token provided')
        return {'message': 'No Authorization Token provided'}, 400
    try:
        id_token = request.headers.get('Authorization')
        auth.verify_id_token(id_token)
    except (ValueError, InvalidIdTokenError, ExpiredIdTokenError, RevokedIdTokenError, CertificateFetchError) as e:
        log.fatal(f'Authorization `id_token` error: {e}')
        return {'message':f'Authorization `id_token` error: {e}'}, 400

    data_payload = request.get_json(force=True)

    if not data_payload.table:
        log.fatal('Payload missing table field.')
        return {'message': 'Payload missing table field'}, 422

    if not data_payload.search_by:
        log.fatal('Payload missing search_by field.')
        return {'message': 'Payload missing search_by field'}, 422
    
    return ********.main(data_payload)
想法/问题:

guard let user = Auth.auth(app: authAppToUse).currentUser else { fatalError("SearchMySQL -> user: \(String(describing: Auth.auth(app: authAppToUse).currentUser))") }
user.getIDTokenForcingRefresh(true) { (idToken, err) in
    if err != nil{
        fatalError("SearchMySQL -> user.getIDToken -> err: \(String(describing: err))")
    }

    guard let guardedIdToken = idToken else { fatalError("SearchMySQL -> guardedIdToken: \(String(describing: idToken))") }
    let rawJSON = [
        "data" : [
            "table": table,
            "search_by": searchBy,
            "search_by_value": searchByValue
        ]
    ]

    guard let guardedJSON = try? JSONSerialization.data(withJSONObject: rawJSON, options: .prettyPrinted) else {
        return
    }

    guard let url = URL(string: "https://us-east1-fresh-customer-dev-ocean.cloudfunctions.net/mysql_search") else { return }
    var request = URLRequest(url: url)
    request.addValue("Bearer \(idToken)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    request.httpBody = guardedJSON

    let task = URLSession.shared.dataTask(with: request) { (data, response, err) in
        if err != nil {
            print(err?.localizedDescription)
            fatalError("SearchMySQL -> URLSession.shared.dataTask -> err: \(String(describing: err))")
        }
        guard let guardedData = data else {
              return
        }

        print(idToken)
        print(response.debugDescription)

        let json = try? JSONSerialization.jsonObject(with: guardedData, options: .allowFragments)
        print(json)

        completion(data)
    }
    task.resume()
}
def main(request):
    """Background Http Triggered Cloud Function for ********.
    Validates authentication with Firebase ID token

    Returns:
        ********.main(payload): http response code and data payload (or message)
    """

    # validate request authorization
    if not request.headers.get('Authorization'):
        log.fatal('No Authorization Token provided')
        return {'message': 'No Authorization Token provided'}, 400
    try:
        id_token = request.headers.get('Authorization')
        auth.verify_id_token(id_token)
    except (ValueError, InvalidIdTokenError, ExpiredIdTokenError, RevokedIdTokenError, CertificateFetchError) as e:
        log.fatal(f'Authorization `id_token` error: {e}')
        return {'message':f'Authorization `id_token` error: {e}'}, 400

    data_payload = request.get_json(force=True)

    if not data_payload.table:
        log.fatal('Payload missing table field.')
        return {'message': 'Payload missing table field'}, 422

    if not data_payload.search_by:
        log.fatal('Payload missing search_by field.')
        return {'message': 'Payload missing search_by field'}, 422
    
    return ********.main(data_payload)
  • Firebase ID令牌不等于Google ID令牌吗
  • 是否存在(自动生成的)的iAM权限问题 firebase服务帐户
  • 我是否还需要向idtoken添加任何plist值 在标题中发送它
  • 这可能与我的云功能规则有关吗
  • 我是否遗漏了什么,或者这是有意/预期的行为?具有 http可调用函数是常规http函数,但具有协议 打包方便,我觉得这是一个比较容易的方法 实施
  • 我想到了使用管理函数发送电子邮件的方法 发送给移动实例的消息,该移动实例在运行期间需要google id令牌 登录,但开销和延迟会导致问题

  • 你试过邮递员吗?我确实认为Id标记部分是正确的。我没有试过与邮递员联系。我刚刚将成员角色编辑为“allUsers”,它起作用了,但“allAuthenticatedUsers”没有。这跟这事有关系吗?因此,如果这是它工作的唯一方式,那么firebase id令牌在技术上不等同于(或可用作)gcp id令牌来查看您的场景,您是否使用任何文档来执行此操作?是的,官方gcp文档:要进一步查看此场景,请提供无法验证的访问令牌的详细日志,特别是403?