65.9K
CodeProject 正在变化。 阅读更多。
Home

如何在ASP.NET Web API应用程序中集成ApiFrame

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (8投票s)

2014年5月1日

CPOL

6分钟阅读

viewsIcon

32170

downloadIcon

954

关于如何将 ApiFrame 集成到 Web API 应用程序中的指南。

引言

本文将提供关于如何将ApiFrame集成到ASP.NET Web API项目的一些指导。ApiFrame是一个简单的.NET库,为实现Web API安全(HMAC认证)、异常处理和Web API方法版本控制提供支持。该库就像一个插件组件,您可以轻松地将其集成到您的应用程序中。您可以在此CodeProject文章中找到ApiFrame的源代码和相关信息。

ApiFrame:一个用于Web API安全、异常和版本控制的简单库[^]

我将带领您了解一个简单的Web API示例应用程序,该应用程序实现了POST和GET方法,用于演示认证、授权、版本控制和异常处理。此外,我将向您介绍如何从API客户端消费该服务。

指南:如何在Web API项目中集成API Frame

首先,让我们创建一个示例应用程序。

  1. 打开Visual Studio 2012
  2. 创建一个新的ASP.NET MVC 4 Web应用程序
  3. 选择Web API项目模板

安装

要安装ApiFrame,请在包管理器控制台中运行以下命令

或者,可以通过Nuget包管理器在项目中引用该库。在解决方案资源管理器中,选择Web API项目 -> 右键单击并打开“管理Nuget包…” -> 在线搜索“ApiFrame”。您将看到以下结果,点击安装按钮,这将把API frame添加到您的项目中。

配置

如果您通过ApiFrame实现认证和授权,那么需要在您的应用程序中实现以下接口。

  • IApiInception

为了演示目的,让我们在Web API项目中执行以下操作

  1. 创建一个名为“ApiFrameConfig”的新文件夹
  2. 在新文件夹内部
    • 创建一个实现“IApiInception”的类“ApiInception”
    • 创建一个实现“IApiException”的类“ApiException”

实现IApiInception

此接口暴露了三个方法。您项目中GetApplicationToken()的实现取决于您的业务模型。如果您将API服务暴露给多个客户,则每个客户都需要有一个访问令牌和秘密令牌。通常,访问令牌和秘密令牌在注册时创建,并与客户共享,以便客户端应用程序与服务进行通信。如果服务暴露给单个客户,则此配置可以添加到Web.config文件中。AuthScheme是授权方案,这可以是一个您保留在Web.Config中的通用标签,或者如果您想为每个客户附加一个缩写名称,则可以使用此属性。这取决于您的选择,但此信息也由库进行验证。因此,AuthScheme是您需要与客户端共享的另一个信息。

为了演示目的,我在我的示例中进行了以下实现。

public ApiApplicationToken GetApplicationToken(string accessToken)
{
    return new ApiApplicationToken()
    {
        AuthScheme = "HMAC",
        AccessToken = "d85aa01c-cf92-4f1e-9862-638fa4ae37b4",
        SecretToken = "06fb3823-b8cc-462b-b855-f655d49eb3e2"
    };
}

认证基于用户名和密码。理想情况下,您项目中的以下方法将调用服务/数据访问层来检查给定的用户名和密码是否有效。为了实现此方法,应为每个现有用户附加一个访问令牌和秘密令牌。如果用户名和密码有效,则该方法应返回一个用户令牌,如以下代码示例所示。这些用户令牌用于授权目的。客户端应用程序可以保留这些令牌,并使用它们发出后续请求以访问授权资源。ApiFrame还支持基于角色的访问。如果您的应用程序不使用基于角色的访问,则Role属性可以为空。

以下代码仅用于演示目的。

public ApiUserToken GetUserToken(string username, string password)
{
    if (username == "demo" && password == "demo123")
    {
        return new ApiUserToken()
        {
            AuthScheme = "HMAC",
            AccessToken = "94d05acb-54de-4e39-9303-3764cabcaf18",
            SecretToken = "88a10072-5fa9-4a8d-b9ac-42966d8da4bc",
            Name = "DemoUser",
            UserId = "001",
            Roles = "Users"
        };
    }

    return null;
}

以下方法用于授权。ApiFrame在授权时调用此方法,将用户的访问令牌作为输入参数传递给该方法。在实际应用程序中,此方法应调用服务或数据访问方法来查询数据库,通过访问令牌获取用户详细信息。该方法使用用户详细信息构建一个ApiUserToken并返回该令牌。

public ApiUserToken GetUserToken(string accessToken)
{
    if (accessToken == "94d05acb-54de-4e39-9303-3764cabcaf18")
    {
        return new ApiUserToken()
        {
            AuthScheme = "HMAC",
            AccessToken = "94d05acb-54de-4e39-9303-3764cabcaf18",
            SecretToken = "88a10072-5fa9-4a8d-b9ac-42966d8da4bc",
            Name = "DemoUser",
            UserId = "001",
            Roles = "Users"
        };
    }

    return null;
}

实现IApiException

通过实现此接口可以捕获异常。

    public class ApiException : IApiException
    {
        public void LogMessage(Exception exception)
        {
            throw new NotImplementedException();
        }
    }

一旦您完成了接口的实现,需要在项目中添加以下配置,将实现(依赖项)注入到库中。在Global.asax文件中,将以下代码包含在Application_Start()中

// ApiFrameConfiguration
ApiObjectFactory.RegisterType<IApiInception, ApiInception>();
ApiObjectFactory.RegisterType<IApiException, ApiException>();
ApiObjectFactory.RegisterType<IApiSignature, ApiSignature>();

示例Web API方法

如果您对Web API方法进行版本控制感兴趣,ApiFrame提供了使用MVC区域或使用命名空间进行版本控制的选项。让我们尝试使用区域。

创建一个名为“V1”的新MVC区域,并在WebApiConfig.cs文件中进行以下配置。这样,您几乎完成了Web API方法的版本控制设置,其余的您需要处理路由。

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Services.Replace(typeof(IHttpControllerSelector), new ApiControllerSelector(config));
        }
    }

在V1中创建以下模型

     public class AccessModel
    {
        public string AccessToken { get; set; }
        public string SecretToken { get; set; }
    }

向项目中添加一个新控制器,并将其命名为“DemoController”。用“ApiException”属性框架DemoController,以允许ApiFrame为您处理异常。

    [ApiException]
    public class DemoController : ApiController
    {

    }

将以下方法添加到DemoController。让我们创建以下方法进行演示。

  • SignIn - 用于认证演示的POST方法
    • 相对路由:/demo/signin
  • GetMessage - 用于授权演示的GET方法
    • 相对路由:/demo/getmessage

您会注意到,下面的SignIn方法是用ApiAuthentication过滤器属性框起来的。同样,GetMessage是用ApiAuthorization过滤器属性框起来的。这些过滤器属性通过调用IApiInception实现的注入方法来处理认证和授权。

[HttpPost]
[ApiAuthentication]
public AccessModel SignIn()
{
    return new AccessModel
    {
        AccessToken = "94d05acb-54de-4e39-9303-3764cabcaf18",
        SecretToken = "88a10072-5fa9-4a8d-b9ac-42966d8da4bc"
    };
}

[HttpGet]
[ApiAuthorization(Roles = "Users")]
public string GetMessage()
{
    string user = ((ApiIdentity)HttpContext.Current.User.Identity).Name;
    return string.Format("Server Message :This is an Authorized Request - LoggedIn User:{0}", user);
}

更新V1AreaRegistration类中的默认路由。

public override void RegisterArea(AreaRegistrationContext context)
{
    context.Routes.MapHttpRoute(
        "V1_default",
        "{area}/{controller}/{action}/{id}",
        new { id = UrlParameter.Optional }
    );
}

运行应用程序,您将看到以下屏幕。我的示例Web API服务正在URL localhost:6360运行

API客户端应使用相同的URL与服务进行通信。

示例API客户端

为了演示目的,让我们从控制台应用程序消费Web API服务。

  1. 打开Visual Studio 2012
  2. 创建控制台应用程序
  3. 添加对System.Net.Http程序集的引用
  4. 通过Nuget包管理器安装以下内容
    • ApiFrame
    • Json.NET

在调用API服务之前,我们需要以下初始设置

// Service Url
string serviceUrl = "https://:6360/";

// Uri version
string apiVersion = "v2";

// Signature Configuration
ApiObjectFactory.RegisterType<IApiSignature, ApiSignature>();

ApiFrame使用HMAC-SHA256算法计算签名。客户端和服务器两端都需要使用相同的算法。为此,我们客户端需要上述签名配置。

服务器将使用令牌识别客户端,因此需要以下配置,并且令牌应与服务器中存储的相同。

// Token Configuration
const string AuthScheme = "HMAC";
const string AccessToken = "d85aa01c-cf92-4f1e-9862-638fa4ae37b4";
const string SecretToken = "06fb3823-b8cc-462b-b855-f655d49eb3e2";

按照以下步骤检查SignIn API服务

  1. 通过控制台读取用户名和密码
  2. 创建包含用户名和密码的POST数据
  3. 使用服务调用所需的参数创建请求令牌
  4. 通过传递服务URL创建ApiClientGateway实例
  5. 通过传递请求令牌调用ApiClientGateway的Execute方法
// Authentication - Sing-in demo - START
Console.WriteLine("\n Authentication -> Sign-in demo - START");
Console.Write("\n\n Enter the Username:");
string userName = Console.ReadLine();
Console.Write(" Enter the Password:");
string password = Console.ReadLine();

string postData = string.Format("Username={0}&Password={1}", userName, password);

ApiRequestToken requestToken = new ApiRequestToken()
{
    Verb = HttpMethod.Post,
    RelativeUrl = string.Format("{0}/demo/signin", apiVersion),
    AccessToken = AppAccessToken,
    SecretToken = AppSecretToken,
    AuthScheme = AuthScheme,
    Content = postData
};

ApiClientGateway apiClientGateway = new ApiClientGateway(serviceUrl);
AccessModel signInResult = null;
try
{
    signInResult = apiClientGateway.Execute<AccessModel>(requestToken);

    if (signInResult != null)
    {
        Console.WriteLine("\n Response from server");
        Console.WriteLine("\n AccessToken:" + signInResult.AccessToken);
        Console.WriteLine(" SecretToken:" + signInResult.SecretToken);
        Console.WriteLine("\n Successfully Authenticated! This is ApiAuthentication Test");
    }
}
catch (ApiRequestException ex)
{
    Console.WriteLine(ex.ErrorResponseMessage.
        Content.ReadAsStringAsync().Result);
}

// Sing-in demo - END

在调用登录服务时,服务器在成功认证后返回一个令牌(访问令牌和秘密令牌)。此令牌被保留并用于后续服务调用。以下是调用授权API服务方法返回私有消息的示例。让我们使用接收到的令牌进行下一次服务调用以获取私有消息

// Authorization -> GetMessage demo - Start

Console.WriteLine("\n Authorization demo -> GetMessage - START");
Console.Read();

if (signInResult != null)
{
    requestToken = new ApiRequestToken()
    {
        Verb = HttpMethod.Get,
        RelativeUrl = string.Format("{0}/demo/GetMessage", apiVersion),
        AccessToken = signInResult.AccessToken,
        SecretToken = signInResult.SecretToken,
        AuthScheme = AuthScheme
    };

    string messageResult = string.Empty;

    try
    {
        messageResult = apiClientGateway.Execute(requestToken);

        if (!string.IsNullOrEmpty(messageResult))
        {
            Console.WriteLine("\n This is ApiAuthorization test");
            Console.WriteLine("Server Response :" + messageResult);
        }
    }
    catch (ApiRequestException ex)
    {
        Console.WriteLine(ex.ErrorResponseMessage.
            Content.ReadAsStringAsync().Result);
    }
}

Console.Read();
// Authorization -> GetMessage demo - End

发生异常时,服务返回ApiRequestException类型的异常。以下显示的是使用错误凭据登录服务调用的屏幕截图。

    catch (ApiRequestException ex)
    {
        Console.WriteLine(ex.ErrorResponseMessage.
            Content.ReadAsStringAsync().Result);
    }

API版本控制演示

在Web API项目中,让我们创建一个新版本的“DemoController”,并添加新版本的SignIn和GetMessage服务。

  1. 创建一个名为“V2”的新MVC区域
  2. 添加一个新的“DemoController”和“AccessModel”
  3. 从V1版本复制SignIn和GetMessage服务
  4. 更新GetMessage服务以包含新版本的消息
  5. 运行应用程序并保持服务启动并运行

在API客户端中,更新apiVersion并运行应用程序。授权服务“GetMessage”现在将返回新版本更新的消息。

© . All rights reserved.