Как передать данные из channel.dart в метод дескриптора промежуточного программного обеспечения?

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

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

Как лучше всего передать карту с информацией о соединении из channel.dart в контроллер Middleware (см. DbConnectionDetails)?

channel.dart

@override
  Future prepare() async {
    logger.onRecord.listen((rec) => print("$rec ${rec.error ?? ""} ${rec.stackTrace ?? ""}"));

    dbConnectionDetails = ConnectionSettings (
      user: "mydbuser",
      password: "mydbpass",
      host: "localhost",
      port: 3306
    );
}

@override
  Controller get entryPoint {
    final router = Router();

    router
      .route("/api/user/query/complex")
      .link(() => AuthMiddleware())
      .link(() => UserComplexQueryController(dbConnectionDetails));
}

В приведенном выше примере я могу передать dbConnectionDetails в конструктор UserComplexQueryController, чтобы я мог использовать его для подключения к базе данных.

Однако если я передам dbConnectionDetails в конструктор AuthMiddleWare, то получу следующую ошибку:

ArgumentError (Неверный аргумент (ы): недопустимый контроллер 'AuthMiddleware'. У контроллеров не должно быть сеттеров, и все поля должны быть помечены как окончательные, или он должен реализовывать 'Recyclable'.)

AuthMiddleWare в моем случае получает токен, проанализированный в URL, и проверит, является ли токен действительным в базе данных. Как вы можете видеть, я не нашел другого способа, кроме как добавить dbConnectionDetails непосредственно в функцию isValid AuthMiddleware. Но я бы предпочел, если бы я мог передать его из channel.dart.

class AuthMiddleware extends Controller {
 // This does not work, as setters not allowed
 //AuthMiddleware(this.dbConnectionDetails);
 //
 //ConnectionSettings dbConnectionDetails

  @override
  Future<RequestOrResponse> handle(Request request) async {
    if (await isValid(request)) {
      return request;
    }
    return Response.unauthorized();
  }

  Future<bool> isValid(Request request) async {
    final String token = request.raw.requestedUri.queryParameters["token"];
    final int timestamp = (DateTime.now().toUtc().millisecondsSinceEpoch / 1000).round();

    ConnectionSettings dbConnectionDetails = ConnectionSettings (
      user: "myuser",
      password: "mypass",
      host: "localhost",
      port: 3306
    );

    AuthTokenDao authTokenDao = new AuthTokenDao(dbConnectionDetails);

    if(await authTokenDao.validateToken(token, timestamp)) {
      return true;
    }

    return false;
  }
}

И да, вы видели правильно. Я подключаюсь к базе данных MySQL:)

1 ответ

Решение

Редактировать CA: Решение (предоставлено Джо Конвей):

class AuthMiddleware extends Controller {
   // Works by adding "final"
   final ConnectionSettings dbConnectionDetails;

   // Now dbConnectionDetails can be passed within the constructor.
   AuthMiddleware(this.dbConnectionDetails);

  @override
  Future<RequestOrResponse> handle(Request request) async {
    if (await isValid(request)) {
      return request;
    }
    return Response.unauthorized();
  }

  Future<bool> isValid(Request request) async {
    final String token = request.raw.requestedUri.queryParameters["token"];
    final int timestamp = (DateTime.now().toUtc().millisecondsSinceEpoch / 1000).round();

    /* Removed this    
    ConnectionSettings dbConnectionDetails = ConnectionSettings (
      user: "myuser",
      password: "mypass",
      host: "localhost",
      port: 3306
    );
    */    
    AuthTokenDao authTokenDao = new AuthTokenDao(dbConnectionDetails);

    if(await authTokenDao.validateToken(token, timestamp)) {
      return true;
    }

    return false;
  }
}
Другие вопросы по тегам