跳转至

创建AuthServer进行身份验证和授权

AuthServer是一个处理创建、验证和刷新授权令牌的服务。你在你的应用程序通道中创建一个AuthServer并注入到处理授权的类型中。这种类型包括:

  • Authorizer: 中间件控制器,可防止端点控制器受到未经授权的访问
  • AuthController: 授予访问令牌的端点控制器
  • AuthCodeController: 端点控制器,授予授权码以换取访问令牌

AuthServer必须持久保存其使用和创建的数据,例如客户端标识符和访问令牌。 存储通常由数据库执行,但是它可以位于内存,缓存或其他某种介质中。 由于存在许多不同的存储介质,因此AuthServer本身不会执行任何存储,它依赖于特定于应用程序的AuthServerDelegate实例。 这使得存储可以独立于验证逻辑。

创建AuthServer和AuthServerDelegate实例

AuthServerDelegateAuthServer用于处理客户端标识符,令牌和其他授权工件的存储的接口。 必须使用AuthServerDelegate的具体实现来创建AuthServer。 Aqueduct包含了使用ORM的AuthServerDelegate的具体实现。 强烈建议使用此实现方式,而不是自己的存储,因为它已经过全面测试并且可以正确清理过期的数据。

这个具体的实现名为ManagedAuthDelegate <T>。 它存在于Aqueduct的一个子包中,必须显式导入。 以下是创建AuthServerManagedAuthDelegate <T>的示例:

import 'package:aqueduct/aqueduct.dart';
import 'package:aqueduct/managed_auth.dart';

class MyApplicationChannel extends ApplicationChannel {  
  AuthServer authServer;

  @override
  Future prepare() async {
    final context = ManagedContext(...);
    final delegate = ManagedAuthDelegate<User>(context);
    authServer = AuthServer(delegate);
  }

  ...
}

(注意,ManagedAuthDelegate有一个类型参数,这将在下一节中介绍。)

尽管AuthServer具有处理授权任务的方法,但很少直接使用它。 而是将AuthCodeControllerAuthController连接到路由,以通过应用程序的HTTP API授予授权令牌。Authorizer的实例在通道中保护路由。所有这些类型都会在AuthServer上调用适当的方法。下面是一个设置和使用授权的ApplicationChannel子类的例子:

import 'package:aqueduct/aqueduct.dart';
import 'package:aqueduct/managed_auth.dart';

class MyApplicationChannel extends ApplicationChannel {
  AuthServer authServer;
  ManagedContext context;

  @override
  Future prepare() async {
    context = ManagedContext(...);
    final delegate = ManagedAuthDelegate<User>(context);
    authServer = AuthServer(delegate);
  }

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

    // 设置认证令牌路由,这将授予和刷新令牌。
    router.route("/auth/token").link(() => AuthController(authServer));

    // 设置身份验证代码路由,授予可以交换令牌的临时访问码
    router.route("/auth/code").link(() => AuthCodeController(authServer));

    // 设置保护路由
    router
      .route("/protected")
      .link(() => Authorizer.bearer(authServer))
      .link(() => ProtectedController());

    return router;
  }
}

有关授权控制器(如 AuthController)的更多细节,请参见授权控制器。有关保护路由的更多细节,请参阅授权器

使用 ManagedAuthDelegate

ManagedAuthDelegate<T>AuthServerDelegate的具体实现,为AuthServer提供授权令牌和客户端的存储。存储是通过Aqueduct的ORM来完成的。ManagedAuthServerDelegate<T>,默认情况下不是标准的aqueduct库的一部分。要使用这个类,应用程序必须导入package:aqueduct/managed_auth.dart

ManagedAuthDelegate<T>的类型参数代表了应用程序对 "用户 "或 "账户 "的概念,OAuth 2.0的术语将这个类型称为资源所有者。一个资源拥有者必须是一个 ManagedObject<T>子类,它是你的应用程序所特有的。它的表定义必须扩展 ResourceOwnerTableDefinition,并且实例类型必须实现ManagedAuthResourceOwner<T>,其中T是表定义。一个基本定义可能看起来像这样:

class User extends ManagedObject<_User>
    implements _User, ManagedAuthResourceOwner<_User> {
}

class _User extends ResourceOwnerTableDefinition {
  @Column(unique: true)
  String email;
}

通过扩展表定义中的 "ResourceOwnerTableDefinition",数据库表具有以下四列:

  • 整数主键,名为 id
  • 唯一的字符串 username
  • 密码的哈希值
  • 用于生成密码哈希值的salt

ResourceOwnerTableDefinition也有一个ManagedSettoken,代表每一个被授予的令牌。

接口ManagedAuthResourceOwner <T>是确保类型参数同时是ManagedObject <T>ResourceOwnerTableDefinition的要求,除了限制ManagedAuthDelegate <T>的类型参数外,没有其他目的。

这种结构允许应用程序声明其自己的“用户”类型,同时仍然满足Aqueduct的OAuth 2.0实现的需求。

managed_auth库还声明了两个ManagedObject <T>子类。 ManagedAuthToken代表授权令牌和授权码的实例,ManagedAuthClient代表OAuth 2.0客户端的实例。 这意味着使用ManagedAuthDelegate <T>的渡槽应用程序至少具有三个数据库表:用户,令牌和客户端。

当不再使用授权令牌和授权代码时,ManagedAuthDelegate <T>将删除它们。 这取决于资源所有者拥有的令牌数量以及令牌的到期日期。 一旦资源所有者获取了40个以上的令牌/代码,最早的令牌/授权码(由到期日期确定)将被删除。 实际上,资源所有者被限制为40个令牌。 实例化ManagedAuthDelegate <T>时可以更改此数字:

final delegate = ManagedAuthDelegate(context, tokenLimit: 20);

配置数据库

ManagedAuthDelegate<T>需要用户、令牌和客户端的数据库表。在你的项目中使用数据库命令行工具来生成迁移脚本,并在数据库中执行。这个工具将查看你的用户类型、ManagedAuthTokenManagedAuthClient的声明,并创建相应的表。