Свифт Сиеста и FirebaseAuth - PullRequest
       14

Свифт Сиеста и FirebaseAuth

0 голосов
/ 15 марта 2020

Я пытаюсь использовать декораторы Siesta для включения потока, в котором мой authToken обновляется автоматически, когда вошедший в систему пользователь получает 401. Для аутентификации я использую Firebase.

В документации Siesta есть прямой пример о том, как связать запросы сиесты, но я не смог найти способ, как получить асинхронную Firebase getIDTokenForcingRefre sh: завершение: здесь. Проблема в том, что Siesta всегда ожидает, что запрос или RequestChainAction будут возвращены, что невозможно с маркером авторизации Firebase refre sh api.

Я понимаю, что цепочка запросов прежде всего сделано для случаев использования только Сиесты. Но есть ли способ использовать асинхронные сторонние API, такие как FirebaseAuth, которые не совсем вписываются в картину?

Вот код:

init() {
    configure("**") {
        $0.headers["jwt"] = self.authToken

        $0.decorateRequests {
          self.refreshTokenOnAuthFailure(request: $1)
     }  
  }

func refreshTokenOnAuthFailure(request: Request) -> Request {
  return request.chained {
    guard case .failure(let error) = $0.response,  // Did request fail…
      error.httpStatusCode == 401 else {           // …because of expired token?
        return .useThisResponse                    // If not, use the response we got.
    }

    return .passTo(
      self.createAuthToken().chained {             // If so, first request a new token, then:
        if case .failure = $0.response {           // If token request failed…
          return .useThisResponse                  // …report that error.
        } else {
          return .passTo(request.repeated())       // We have a new token! Repeat the original request.
        }
      }
    )
  }
}

//What to do here? This should actually return a Siesta request
func createAuthToken() -> Void {
  let currentUser = Auth.auth().currentUser
  currentUser?.getIDTokenForcingRefresh(true) { idToken, error in
    if let error = error {
      // Error
      return;
    }
    self.authToken = idToken
    self.invalidateConfiguration()
  }
}

1 Ответ

0 голосов
/ 29 марта 2020

Во-первых, вам следует перефразировать основной смысл вашего вопроса, чтобы он не определялся Firebase c, в соответствии со словами "Как создать цепочку запросов с произвольным асинхронным кодом вместо запроса?" , Это будет намного более полезным для сообщества таким образом. Затем вы можете упомянуть, что Firebase auth - ваш конкретный c вариант использования. Я собираюсь ответить на ваш вопрос соответственно.

(Редактировать: ответив на этот вопрос, теперь я вижу, что Павел уже ответил на него здесь: Как украсить запрос Siesta асинхронной задачей )

Siesta's RequestDelegate делает то, что вы ищете. Процитируем документы: «Это полезно для того, чтобы взять вещи, которые не являются стандартными сетевыми запросами, и обернуть их так, чтобы они выглядели как Siesta, как будто они есть. Чтобы создать пользовательский запрос, передайте свой делегат Resource.prepareRequest(using:)."

Вы можете использовать что-то вроде этого как грубую отправную точку - он запускает замыкание (вызов auth в вашем случае), которое либо завершается успешно без вывода, либо возвращает ошибку. В зависимости от использования, вы можете адаптировать его для заполнения сущности фактическим содержимым.

// todo better name
class SiestaPseudoRequest: RequestDelegate {
    private let op: (@escaping (Error?) -> Void) -> Void

    init(op: @escaping (@escaping (Error?) -> Void) -> Void) {
        self.op = op
    }

    func startUnderlyingOperation(passingResponseTo completionHandler: RequestCompletionHandler) {
        op {
            if let error = $0 {
                // todo better
                let reqError = RequestError(response: nil, content: nil, cause: error, userMessage: nil)
                completionHandler.broadcastResponse(ResponseInfo(response: .failure(reqError)))
            }
            else {
                // todo you might well produce output at this point
                let ent = Entity<Any>(content: "", contentType: "text/plain")
                completionHandler.broadcastResponse(ResponseInfo(response: .success(ent)))
            }
        }
    }

    func cancelUnderlyingOperation() {}

    func repeated() -> RequestDelegate { SiestaPseudoRequest(op: op) }

    // todo better
    private(set) var requestDescription: String = "SiestaPseudoRequest"
}

Один из обнаруженных мной уловов заключается в том, что преобразователи ответа не запускаются для таких «запросов» - конвейер преобразователя задан c на запрос сети Сиесты. (Это застало меня врасплох, и я не уверен, что мне это нравится, но Сиеста, как правило, полна хороших решений, поэтому я в основном принимаю это на веру, что для этого есть все основания.)

Возможно, стоит обратить внимание на другое поведение, не похожее на запрос.

...