Как выйти из системы (например, отозвать, удалить или аннулировать токены) для пользователя на сервере Aqueduct?

Я знаю, как реализовать маршрут для регистрации пользователя, а также как обменять учетные данные пользователя на токен доступа. Оба они описаны в официальном руководстве.

Как сделать недействительным токен доступа (и токен обновления) для зарегистрированного пользователя. Это необходимо как для выхода из системы, так и для ограничения ущерба в случае взлома учетной записи пользователя.

Я вижу есть способ

authServer.revokeAllGrantsForResourceOwner(identifier)

но я все еще работаю над тем, как получить идентификатор от пользователя, поскольку клиентское приложение знает имя пользователя, но не идентификатор пользователя в базе данных сервера. Было бы неплохо просто передать текущий токен и попросить сервер отменить все токены для этого пользователя.


person Suragch    schedule 21.05.2019    source источник


Ответы (1)


Если вы хотите отозвать все токены для данного токена, возьмите идентификатор пользователя из токена авторизации и выполните запрос на удаление для токенов этого пользователя:

class TokenManagerController extends ResourceController {
  @Operation.delete()
  Future<Response> deleteTokens() async {
    final userId = request.authorization.ownerID;

    final query = Query<ManagedAuthToken>(context)
      ..where((token) => token.resourceOwner).identifiedBy(userId);
    final count = await query.delete();

    return Response.ok({"userId": userId, "tokensDeleted": count});
  }
}

И убедитесь, что вы связываете авторизатор:

router.route("/tokens")
      .link(() => Authorizer.bearer(authServer))
      .link(() => TokenManagerController(context));

FWIW, я рекомендую иметь область действия специально для этого действия, которая предоставляется только для этого сценария через дополнительный вход в систему. UX заключается в том, что пользователь должен снова ввести свой пароль.

Если вы просто хотите удалить один токен, просто запустите запрос на удаление, где access_token = токен в заголовке авторизации.

class LogoutController extends ResourceController {
  @Operation.delete()
  Future<Response> deleteTokens(@Bind.header('authorization') String authHeader) async {

    final parser = AuthorizationBearerParser();
    final userToken = parser.parse(authHeader);

    final query = Query<ManagedAuthToken>(context)
      ..where((token) => token.accessToken).equalTo(userToken);
    final count = await query.delete();

    final userId = request.authorization.ownerID;
    return Response.ok({"userId": userId, "tokensDeleted": count});
  }
}
person Joe Conway    schedule 22.05.2019
comment
Это очень полезно. Спасибо. Хотя, возможно, я не понимаю UX. Не принято вводить пароль перед выходом из системы. Это заставляет меня думать, что приведенный выше код предназначен для более исключительной ситуации, чем просто выход из системы. Это правда? Для выхода, возможно, все, что мне нужно сделать, это удалить токен на стороне клиента. - person Suragch; 22.05.2019
comment
Ответ здесь был полезен, но я все еще не уверен, следует ли мне удалять токены на сервере Aqueduct при выходе из системы. В некоторой степени сервер Aqueduct не является RESTful (в моем понимании), поскольку он сохраняет информацию токена пользователя. - person Suragch; 22.05.2019
comment
Ах, если вы просто хотите удалить один токен, просто запустите запрос на удаление, где access_token = токен в заголовке авторизации. Я не уверен, что слежу за частью «RESTful»; независимо от того, хранится ли токен где-то или это токен без состояния (например, JWT), не влияет на безгражданство API. Приложение по-прежнему не имеет гражданства; вы можете создать любое количество экземпляров, и все они будут вести себя одинаково, и вы можете использовать токен, полученный от одного экземпляра вашего API, с другим экземпляром. Если хранение данных в базе данных сделало ваш API отслеживающим состояние, ни одно приложение не было бы без состояния. - person Joe Conway; 22.05.2019
comment
Хорошо, я смог сделать это с ..where((token) => token.accessToken).equalTo(userToken);. Показан ли где-либо токен на предъявителя в запросе? Очевидно, этого нет в request.authorization. Чтобы получить userToken, мне пришлось сделать @Bind.header('authorization'), а затем использовать AuthorizationBearerParser, чтобы получить токен. - person Suragch; 22.05.2019
comment
И последний вопрос. Я не вижу практической разницы между удалением только текущего токена и всех старых токенов. Есть ли? - person Suragch; 22.05.2019
comment
Да, разница в том, что токены предоставляются нескольким клиентам. У вас может быть токен, предоставленный вашему браузеру, но у вас также может быть долгоживущий токен, предоставленный для учетной записи службы и вашего мобильного приложения. Я бы избегал терминологии «текущий токен» - может быть несколько «текущих токенов». - person Joe Conway; 28.05.2019
comment
В этом есть смысл. Спасибо. - person Suragch; 28.05.2019
comment
Что касается моего вопроса о получении токена на предъявителя, я добавил к вашему ответу раздел, в котором, как я понял, вы говорите. Пожалуйста, дайте мне знать, есть ли более прямой способ получить токен на предъявителя. - person Suragch; 28.05.2019