异步 SSPI 安全上下文允许调用方在不阻止的情况下继续,并在调用完成后接收通知。 目前,仅内核模式 TLS 客户端和服务器支持异步上下文。 以下异步 SSPI 函数对异步安全上下文进行作:
异步上下文管理类型
对象名称 | 描述 |
---|---|
SspiAsyncNotifyCallback | 用于通知异步 SSPI 调用完成的回调。 |
异步上下文管理功能
API 名称 | 描述 |
---|---|
SspiCreateAsyncContext | 创建用于跟踪异步调用的 SspiAsyncContext 实例。 |
SspiReinitAsyncContext | 标记异步上下文以供重复使用。 |
SspiSetAsyncNotifyCallback | 注册在异步调用完成时收到通知的回调。 |
SspiAsyncContextRequiresNotify | 确定给定异步上下文是否需要在调用完成时发出通知。 |
SspiGetAsyncCallStatus | 获取与提供的上下文关联的异步调用的当前状态。 |
SspiFreeAsyncContext | 释放在调用 SspiCreateAsyncContext 函数时创建的上下文。 |
异步 SSPI 函数
除了与同步上下文相同的所有参数外,以下函数还接受异步上下文。
API 名称 | 描述 |
---|---|
SspiAcquireCredentialsHandleAsync | 异步获取用于预先存在的安全主体凭据的句柄。 |
SspiAcceptSecurityContextAsync | 允许传输应用程序的服务器组件在服务器和远程客户端之间异步建立安全上下文。 |
SspiInitializeSecurityContextAsync | 初始化异步安全上下文。 |
SspiDeleteSecurityContextAsync | 删除与之前调用 SspiInitializeSecurityContextAsync 函数或 SspiAcceptSecurityContextAsync 函数所发起的指定安全上下文关联的本地数据结构。 |
SspiFreeCredentialsHandleAsync | 释放凭据句柄。 |
API 示例
典型的调用流如下所示:
- 创建 SspiAsyncContext 上下文以使用 SspiCreateAsyncContext 跟踪调用
- 为上下文注册 SspiAsyncNotifyCallback
- 使用 SspiAcceptSecurityContextAsync 进行异步调用
- 在回调时,使用 SspiGetAsyncCallStatus 检索结果
- 使用 SspiDeleteSecurityContextAsync删除 SspiAsyncContext。 如果使用 SspiReinitAsyncContext重用上下文,请返回到步骤 2。
下面的示例演示 SspiAcceptSecurityContextAsync 的调用。 示例等待调用完成并检索结果。
在完整的 SSPI 握手中,将多次调用 SspiAcceptSecurityContextAsync 和 SspiInitializeSecurityContextAsync,直到返回SEC_E_OK。 SspiReinitAsyncContext 已提供方便使用,并在本例中促进性能。
断言用于突出显示在成功的情况下预期的内容。
#include <sspi.h>
void AsyncCallCompleted(
_In_ SspiAsyncContext* AsyncContext,
_In_opt_ PVOID pCallbackData
)
{
// Get result.
SECURITY_STATUS Status = SspiGetAsyncCallStatus(AsyncContext);
ASSERT(SEC_E_OK == Status);
// *Perform any needed callback actions, use pCallbackData if needed*
// Clean up async context when done.
SspiFreeAsyncContext(AsyncContext);
}
void DoASCCall(
_In_opt_ PCredHandle phCred,
_In_opt_ PCtxtHandle phContext,
_In_opt_ PSecBufferDesc pInput,
_In_opt_ PSecBufferDesc pOutput,
_Out_ unsigned long* pfContextAttr,
_Out_opt_ PTimeStamp ptsExpiry
)
{
// Create context for async call
SspiAsyncContext* AsyncContext = SspiCreateAsyncContext();
// Check for out of memory condition
ASSERT(AsyncContext);
// Register callback that continues execution upon completion.
PVOID pCallbackData = … ; // *Setup any state needed for callback.*
SECURITY_STATUS Status = SspiSetAsyncNotifyCallback(AsyncContext,
AsyncCallCompleted,
pCallbackData);
ASSERT(SEC_E_OK == Status);
// Queue asynchronous call.
Status = SspiAcceptSecurityContextAsync(AsyncContext,
phCred,
phContext,
pInput,
ASC_REQ_CONNECTION,
SECURITY_NATIVE_DREP,
phContext,
pOutput,
pfContextAttr,
ptsExpiry);
// All async functions return the status of queueing the async call,
// not the call’s result.
ASSERT(SEC_E_OK == Status);
// At this point, the call can be pending or complete.
// If complete, the result or error is returned.
// For this example, we assume if it finished, it finished with SEC_E_OK.
Status = SspiGetAsyncCallStatus(AsyncContext);
ASSERT(SEC_I_ASYNC_CALL_PENDING == Status ||
SEC_E_OK == Status);
// Execution will continue in the callback upon completion
}