如何将数据从 channel.dart 传递到中间件句柄方法?

How can I pass data from channel.dart to a middleware handle method?

我创建了一个中间件控制器,负责身份验证。控制器将链接在资源控制器的前面。我认为这是正确的方法吗?

在 handle 方法中,我正在执行一个需要连接信息的数据库查询。但是,当我尝试通过构造函数传递数据时,它告诉我不允许设置器。

将带有连接信息的映射从 channel.dart 传递到中间件控制器(请参阅 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 (Invalid argument(s): Invalid controller 'AuthMiddleware'. Controllers must not have setters and all fields must be marked as final, or it must implement 'Recyclable'.)

在我的例子中,AuthMiddleWare 正在获取一个在 URL 中解析的令牌,并将检查该令牌在数据库中是否有效。如您所见,除了直接在 AuthMiddleware isValid 函数中添加 dbConnectionDetails 之外,我没有找到其他方法。但我更愿意,如果我能把它从 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 数据库 :)

CA 编辑:解决方案(由 Joe Conway 提供):

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;
  }
}