使用自定义 API 密钥认证保护 ASP.NET CORE Web API






4.79/5 (40投票s)
在本文中,我们将学习如何在 ASP.NET Core MVC 中创建一个安全的 Web API。
在快速发展的 Web 技术时代,一切都变化得太快了。对于 ASP.NET,曾经有一段时间我们使用 Web 服务(那些 .asmx 文件),它是基于 SOAP 的,我们只能用它来从其他应用程序消费数据,安全性并不高。大多数开发人员会将用户名和密码作为输入参数,然后才允许访问 Web 服务。
随着时间的推移,微软推出了 WCF,它虽然安全但使用起来过于复杂。
此外,微软又推出了名为 Web API 的新东西,我们可以通过创建 ASP.NET MVC 应用程序或直接 ASP.NET Web API 应用程序来使用它,它更轻量且易于使用。
但进一步,微软推出了 ASP.NET Core,它比所有之前的版本都更轻量。
但在 ASP.NET WEB API 中,当我们说要保护 Web API 时,我们使用委托处理程序来验证 API 请求。
当我们进入 ASP.NET Core 时,不再有处理程序和模块,我们引入了名为中间件的新概念,我们将编写它来验证 API 请求。
在本文中,我们将学习额外的部分,即创建一个 ASP.NET Core WEB API 应用程序的过程,其中开发者可以登录应用程序并订阅自己的服务,然后生成 API 密钥,查看自己的 API 文档以了解如何消费 API,最后他将获得自己每月发送请求次数的分析。如果发送请求次数超过用户订阅的限制,他将收到“超出请求长度”的响应。
进程
- 注册开发者
- 登录
- 选择最大请求数服务(1000 请求,5000 请求)
- 获取 API 密钥
- API 文档
- 使用 API 密钥访问服务
必备组件
- Visual Studio 2017 和 ASP.NET CORE 2.0
- SQL Server 2008 及更高版本
数据库部分
在这部分中,我们创建了名为“MoviesDB
”的数据库,它有七个表,我们将在应用程序中使用它们。
表详情
APIManagerTB
:存储所有服务和 API 密钥MoviesTB
:存储所有电影详情MusicTB
:存储所有音乐详情RegisterUser
:存储所有注册用户详情ServicesTB
:存储所有服务详情LoggerTB
:存储所有 API 请求日志HitsTB
:存储所有请求值(1000 请求,2000 请求)
创建 WEB API 应用程序
打开新的 Visual Studio 2017 IDE。
打开 IDE 后,接下来我们将创建 ASP.NET MVC Core 项目。为此,只需点击 文件 - 新建 - 项目。
选择项目后,将弹出一个名为“新建项目”的新对话框。在该对话框中,我们将选择 Visual C# 项目模板 - .NET Core - ASP.NET Core Web 应用程序。然后,我们将项目命名为“MoviesAPIStore
”。
项目命名后,点击 确定 按钮创建项目。将弹出一个新对话框,用于选择创建“Web 应用程序 (模型-视图-控制器)”的模板,点击 确定 按钮创建项目。
配置项目后,接下来我们将查看项目结构。
使用 Entity Framework Core Code First 方法连接应用程序到数据库
第一步,我们将在 appsettings.json 文件中添加连接字符串。
第二步,我们将根据 MoviesDB
数据库创建模型。
第三步,我们将添加一个 MoviesContext 文件夹,并在该文件夹内添加一个将继承 Dbcontext
类的 DatabaseContext
类。
DatabaseContext 类的代码片段
using Microsoft.EntityFrameworkCore;
using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.MoviesContext
{
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
}
public DbSet<RegisterUser> RegisterUser { get; set; }
public DbSet<ServicesTB> ServicesTB { get; set; }
public DbSet<HitsTB> HitsTB { get; set; }
public DbSet<APIManagerTB> APIManagerTB { get; set; }
public DbSet<MoviesTB> MoviesTB { get; set; }
public DbSet<MusicTB> MusicTB { get; set; }
public DbSet<LoggerTB> LoggerTB { get; set; }
}
}
向应用程序添加 Repository 文件夹
在这部分,我们将向项目添加 Repository 文件夹。在这个文件夹中,我们将存放所有项目接口和具体类。
注册用户
RegisterUser
模型- 添加
IRegisterUser
接口 - 添加
RegisterUserConcrete
类 - 添加控制器
- 添加视图
- 在启动类中设置依赖注入,用于注入
RegisterUserConcrete
类的依赖项
让我们从 RegisterUser
模型开始。
1. RegisterUser 模型
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Models
{
[Table("RegisterUser")]
public class RegisterUser
{
[Key]
public long UserID { get; set; }
[Required(ErrorMessage = "Required Username")]
[StringLength(30, MinimumLength = 2,
ErrorMessage = "Username Must be Minimum 2 Charaters")]
public string Username { get; set; }
[DataType(DataType.Password)]
[Required(ErrorMessage = "Required Password")]
[MaxLength(30, ErrorMessage = "Password cannot be Greater than 30 Charaters")]
[StringLength(31, MinimumLength = 7,
ErrorMessage = "Password Must be Minimum 7 Charaters")]
public string Password { get; set; }
public DateTime CreateDate { get; set; }
[Required(ErrorMessage = "Required EmailID")]
[RegularExpression(@"[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}",
ErrorMessage = "Please enter Valid Email ID")]
public string EmailID { get; set; }
}
}
完成添加 RegisterUser
模型后,接下来我们将添加 IRegisterUser
接口,并在此接口中声明注册用户所需的所有方法。
2. IRegisterUser 接口
在这部分,我们将向 repository 文件夹添加 IRegisterUser
接口,此接口包含四个方法。
Add
:用于创建一个新用户,它将RegisterUser
模型作为输入。ValidateRegisteredUser
:用于验证用户输入的用户名和密码。ValidateUsername
:用于验证用户输入的Username
(数据库中是否已存在类似的Username
)。GetLoggedUserID
:根据用户输入的用户名和密码获取已登录的UserID
。
代码片段
using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Repository
{
public interface IRegisterUser
{
void Add(RegisterUser registeruser);
bool ValidateRegisteredUser(RegisterUser registeruser);
bool ValidateUsername(RegisterUser registeruser);
long GetLoggedUserID(RegisterUser registeruser);
}
}
3. RegisterUserConcrete 类
RegisterUserConcrete
类将继承 IRegisterUser
接口并实现其中的所有方法。
RegisterUserConcrete 类的代码片段
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Repository
{
public class RegisterUserConcrete : IRegisterUser
{
private DatabaseContext _context;
public RegisterUserConcrete(DatabaseContext context)
{
_context = context;
}
public void Add(RegisterUser registeruser)
{
try
{
registeruser.UserID = 0;
_context.RegisterUser.Add(registeruser);
_context.SaveChanges();
}
catch (Exception ex)
{
throw;
}
}
public long GetLoggedUserID(RegisterUser registeruser)
{
var usercount = (from User in _context.RegisterUser
where User.Username == registeruser.Username &&
User.Password == registeruser.Password
select User.UserID).FirstOrDefault();
return usercount;
}
public bool ValidateRegisteredUser(RegisterUser registeruser)
{
var usercount = (from User in _context.RegisterUser
where User.Username == registeruser.Username &&
User.Password == registeruser.Password
select User).Count();
if (usercount > 0)
{
return true;
}
else
{
return false;
}
}
public bool ValidateUsername(RegisterUser registeruser)
{
var usercount = (from User in _context.RegisterUser
where User.Username == registeruser.Username
select User).Count();
if (usercount > 0)
{
return true;
}
else
{
return false;
}
}
}
}
添加完 RegisterUserConcrete
类后,接下来我们将了解依赖注入。
理解依赖注入
在此过程中,我们将使用构造函数注入来注入依赖项。
我们将 DbContext
作为依赖项注入到 RegisterUserConcrete
类中,以访问特定的实体(RegisterUser
)。
注入 Dbcontext 时的快照
看完了 DatabaseContext
注入,你可能会想我是如何注入依赖的,对吧?ASP.NET Core MVC 自带了内置的依赖注入框架,你只需要配置它,它位于 startup.cs 文件中的 ConfigureServices
方法下。
配置依赖
在上面的快照中,您可以看到我们已经配置了 DatabaseContext
依赖项,无论何时您使用 DatabaseContext
类,DbContext
实例都将被注入。
您还可以看到我们添加了 services.Configure
方法。这用于获取连接字符串作为依赖项,我们通过“Configuration.GetSection("ConnectionStrings")
”获取连接字符串——我们将使用此连接字符串与 Dapper ORM 配合使用。
我们添加的最后一个依赖项是 AddTransient
。在这里,我们需要配置一个接口和一个具体类。
代码片段
services.AddTransient<Interface, ConcreteClass>();
每当我们使用接口时,具体类的实例将通过依赖注入框架注入。
现在我们已经配置了 IRegisterUser
接口和 RegisterUserConcrete
具体类的依赖项。
随着我们继续,我们将以与 IRegisterUser
接口和 RegisterUserConcrete
具体类相同的方式在 ConfigureServices
方法中注册更多的依赖项。
什么是具体类?
继承接口的类称为具体类。
在 .NET 的依赖注入中,主要有三种生命周期
- 单例(Singleton)在整个应用程序中创建单个实例。它在第一次创建实例,并在所有调用中重用同一个对象。
- 作用域(Scoped)生命周期服务在作用域内每个请求创建一次。它等同于当前作用域内的单例。例如,在 MVC 中,它为每个 HTTP 请求创建一个实例,但在同一个 Web 请求内的其他调用中使用相同的实例。
- 瞬态(Transient)生命周期服务每次请求时都会创建。这种生命周期最适合轻量级、无状态服务。
完成理解依赖注入配置后,让我们添加 RegisterUser Controller
。
4. 添加 RegisterUser 控制器
要添加控制器,只需右键点击 controller 文件夹,然后选择 -> 添加 -> 在其中选择 添加新项。将弹出一个名为 添加新项 的新对话框。在其中,选择“MVC 控制器类”并将控制器命名为“RegisterUserController
”,然后点击 添加 按钮创建 RegisterUser
控制器。
创建控制器后,接下来我们将使用构造函数注入来注入依赖项。
为此,我们将添加一个构造函数,它将 IRegister
接口作为输入,运行时,依赖注入将注入 IRegister
接口的依赖项,即 RegisterUserConcrete
。
RegisterUserController 的代码片段
using System;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Repository;
using MoviesAPIStore.Models;
using MoviesAPIStore.AES256Encryption;
// For more information on enabling MVC for empty projects,
// visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace MoviesAPIStore.Controllers
{
public class RegisterUserController : Controller
{
IRegisterUser _repository;
public RegisterUserController(IRegisterUser repository)
{
_repository = repository;
}
[HttpGet]
// GET: RegisterUser/Create
public ActionResult Create()
{
return View(new RegisterUser());
}
// POST: RegisterUser/Create
[HttpPost]
public ActionResult Create(RegisterUser RegisterUser)
{
try
{
if (!ModelState.IsValid)
{
return View("Create", RegisterUser);
}
// Validating Username
if (_repository.ValidateUsername(RegisterUser))
{
ModelState.AddModelError("", "User is Already Registered");
return View("Create", RegisterUser);
}
RegisterUser.CreateDate = DateTime.Now;
// Encrypting Password with AES 256 Algorithm
RegisterUser.Password = EncryptionLibrary.EncryptText(RegisterUser.Password);
// Saving User Details in Database
_repository.Add(RegisterUser);
TempData["UserMessage"] = "User Registered Successfully";
ModelState.Clear();
return View("Create", new RegisterUser());
}
catch
{
return View();
}
}
}
}
在 RegisterUser
控制器中,我们添加了两个用于创建的动作方法,一个用于处理 [HttpGet]
请求,另一个用于处理 [HttpPost]
请求。在 [HttpPost]
请求中,我们将首先验证 Username
是否已存在,如果不存在,则创建用户,接下来我们还将密码作为输入,而不能以明文形式存储在数据库中。我们需要将其以加密格式存储,为此,我们将使用 AES 256 算法。
5. RegisterUser 视图
注意:注册用户后,以下详细信息将存储在 RegisterUser
表中。
6. RegisterUser 表
完成注册部分后,接下来我们将创建一个登录页面。
登录
在这部分,我们将创建一个登录控制器,包含两个操作方法。一个用于处理 get
请求,另一个用于处理 post
请求,我们也将以相同的方式添加登录视图。
在 LoginController
的控制器部分,我们将使用依赖注入来注入 RegisterUserConcrete
的依赖项,以便我们可以访问其中的方法。
我们将使用“ValidateRegisteredUser
”方法来验证用户凭据。如果用户有效,我们将把请求推送到仪表板页面,否则我们将在登录页面显示错误。
LoginController 的代码片段
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.AES256Encryption;
using MoviesAPIStore.Models;
using MoviesAPIStore.Repository;
using System;
namespace MoviesAPIStore.Controllers
{
public class LoginController : Controller
{
IRegisterUser _IRegisterUser;
public LoginController(IRegisterUser IRegisterUser)
{
_IRegisterUser = IRegisterUser;
}
public ActionResult Login()
{
return View(new RegisterUser());
}
[HttpPost]
public ActionResult Login(RegisterUser RegisterUser)
{
try
{
if (string.IsNullOrEmpty(RegisterUser.Username) &&
(string.IsNullOrEmpty(RegisterUser.Password)))
{
ModelState.AddModelError("", "Enter Username and Password");
}
else if (string.IsNullOrEmpty(RegisterUser.Username))
{
ModelState.AddModelError("", "Enter Username");
}
else if (string.IsNullOrEmpty(RegisterUser.Password))
{
ModelState.AddModelError("", "Enter Password");
}
else
{
RegisterUser.Password =
EncryptionLibrary.EncryptText(RegisterUser.Password);
if (_IRegisterUser.ValidateRegisteredUser(RegisterUser))
{
var UserID = _IRegisterUser.GetLoggedUserID(RegisterUser);
HttpContext.Session.SetString("UserID", Convert.ToString(UserID));
return RedirectToAction("Dashboard", "Dashboard");
}
else
{
ModelState.AddModelError("", "User is Already Registered");
return View("Login", RegisterUser);
}
}
return View("Login", RegisterUser);
}
catch(Exception)
{
return View();
}
}
public ActionResult Logout()
{
HttpContext.Session.Clear();
return RedirectToAction("Login", "Login");
}
}
}
登录后,我们将看到一个带图表的简单仪表板页面。
仪表板页面
这是一个简单的仪表板页面,我将在接下来的步骤中详细解释。
看完仪表板页面后,您可以看到我们有 生成 API 密钥菜单。接下来我们将创建一个生成 API 密钥页面,用户可以在其中为 API 生成密钥。
生成 API 密钥
添加 ApplicationKeys 控制器
在 ApplicationKeysController
中,我们将添加两个名为 GenerateKeys
的操作方法,一个用于处理 get
请求,另一个用于处理 post
请求。
在 GenerateKeys
页面上,我们将添加两个下拉列表,一个用于显示服务,另一个用于显示最大请求数。
用户选择这些下拉列表后,将点击 创建 API 密钥 按钮生成 API 密钥以访问这些 API。
让我们看看 GenerateKeysVM
模型。
GenerateKeysVM 模型代码片段
using MoviesAPIStore.Filters;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Models
{
public class GenerateKeysVM
{
[Required(ErrorMessage ="Choose Service")]
[ServiceValidate]
public int? ServiceID { get; set; }
[HitValidate]
[Required(ErrorMessage = "Choose Max Request")]
public int? HitsID { get; set; }
public List<HitsTB> ListHits { get; set; }
public List<ServicesTB> ListServices { get; set; }
public string APIKey { get; set; }
}
}
添加 GenerateKeysVM
模型后,接下来我们将添加 ServicesStore
接口和 Concrete
类。
IServicesStore 接口
在 IServicesStore
接口中,我们添加了两个方法 GetServiceList
和 GetServiceListforDashboard
。
IServicesStore 接口的代码片段
using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Repository
{
public interface IServicesStore
{
List<ServicesTB> GetServiceList();
List<ServicesTB> GetServiceListforDashboard();
}
}
添加 IServicesStore
接口后,接下来我们将添加 ServicesStore
Concrete
类。
ServicesStoreConcrete 类的代码片段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
namespace MoviesAPIStore.Repository
{
public class ServicesStoreConcrete : IServicesStore
{
private DatabaseContext _context;
public ServicesStoreConcrete(DatabaseContext context)
{
_context = context;
}
public List<ServicesTB> GetServiceList()
{
try
{
var ServiceList = (from services in _context.ServicesTB
select services).ToList();
ServiceList.Insert(0, new ServicesTB
{ ServiceName = "---Choose Service---", ServiceID = -1 });
return ServiceList;
}
catch (Exception)
{
throw;
}
}
public List<ServicesTB> GetServiceListforDashboard()
{
try
{
var ServiceList = (from services in _context.ServicesTB
select services).ToList();
return ServiceList;
}
catch (Exception)
{
throw;
}
}
}
}
完成添加 IServicesStore
接口和 ServicesStoreConcrete
类后,接下来我们将添加 Ihits
接口。
添加 Ihits 接口
Ihits
接口包含用于显示 HitsList
(最大请求下拉列表)和用于在仪表板上显示图表的方法。
Ihits 接口的代码片段
using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Repository
{
public interface IHits
{
List<HitsTB> GetHitsList();
List<string> GetChartsMoviesreport();
List<string> GetChartsMusicreport();
}
}
添加 HitsConcrete 类
在这部分,我们实现了在 IHits
接口中声明的所有方法。在此具体类的某些方法中,我们使用了 Dapper ORM 从数据库获取数据。您可以看到此类的构造函数接受两个输入,一个 DatabaseContext
和一个 IOptions<ConnectionStrings>
,DatabaseContext
将获取 DbContext
的实例,而 IOptions<ConnectionStrings>
将获取配置(连接字符串)的实例。
HitsConcrete 类的代码片段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using Dapper;
using System.Data.SqlClient;
using Microsoft.Extensions.Options;
namespace MoviesAPIStore.Repository
{
public class HitsConcrete : IHits
{
private DatabaseContext _context;
private ConnectionStrings _connectionstrings;
public HitsConcrete(DatabaseContext context,
IOptions<ConnectionStrings> connectionstrings)
{
_context = context;
_connectionstrings = connectionstrings.Value;
}
public List<HitsTB> GetHitsList()
{
try
{
var hitsList = (from services in _context.HitsTB select services).ToList();
hitsList.Insert(0, new HitsTB
{ HitsDisplay = "---Choose Max Request---", HitsID = -1 });
return hitsList;
}
catch (Exception)
{
throw;
}
}
public List<string> GetChartsMoviesreport()
{
try
{
using (SqlConnection con = new SqlConnection
(Convert.ToString(_connectionstrings.DatabaseConnection)))
{
var parameter = new DynamicParameters();
return con.Query<string>("Usp_GetChartsMoviesreport",
null, null, false,0, System.Data.CommandType.StoredProcedure).ToList();
}
}
catch (Exception)
{
throw;
}
}
public List<string> GetChartsMusicreport()
{
try
{
using (SqlConnection con = new SqlConnection
(Convert.ToString(_connectionstrings.DatabaseConnection)))
{
var parameter = new DynamicParameters();
return con.Query<string>("Usp_GetChartsMusicreport",
null, null, false, 0, System.Data.CommandType.StoredProcedure).ToList();
}
}
catch (Exception)
{
throw;
}
}
}
}
添加 IHits
接口和 HitsConcrete
类后,接下来我们将添加 IAPIManager
接口。
添加 IAPIManager 接口
在此接口中,我们将添加生成、保存和验证 API 密钥所需的方法。此外,我们还添加了两个方法:Deactivate
和 Reactivate
服务,用户可以使用它们激活和停用自己的服务。
IAPIManager 接口的代码片段
using MoviesAPIStore.Models;
namespace MoviesAPIStore.Repository
{
public interface IAPIManager
{
int isApikeyAlreadyGenerated(int? ServiceID, int? UserID);
int GenerateandSaveToken(APIManagerTB APIManagerTB);
APIManagerVM GetApiDetailsbyServiceIDandUserID(int? ServiceID, int? UserID);
int DeactivateService(int? ServiceID, int? UserID);
int ReactivateService(int? ServiceID, int? UserID);
}
}
添加 IAPIManager
接口后,接下来我们将添加实现 IAPIManager
的 APIManagerConcrete
类。
APIManagerConcrete 的代码片段
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using System;
using System.Data.SqlClient;
using System.Linq;
namespace MoviesAPIStore.Repository
{
public class APIManagerConcrete : IAPIManager
{
private DatabaseContext _context;
private ConnectionStrings _connectionstrings;
public APIManagerConcrete(DatabaseContext context,
IOptions<ConnectionStrings> connectionstrings)
{
_context = context;
_connectionstrings = connectionstrings.Value;
}
public int isApikeyAlreadyGenerated(int? ServiceID, int? UserID)
{
try
{
var keyCount = (from apimanager in _context.APIManagerTB
where apimanager.ServiceID == ServiceID &&
apimanager.UserID == UserID
select apimanager).Count();
return keyCount;
}
catch (Exception)
{
throw;
}
}
public int GenerateandSaveToken(APIManagerTB APIManagerTB)
{
try
{
_context.APIManagerTB.Add(APIManagerTB);
return _context.SaveChanges();
}
catch (Exception)
{
throw;
}
}
public APIManagerVM GetApiDetailsbyServiceIDandUserID(int? ServiceID, int? UserID)
{
try
{
using (SqlConnection con = new SqlConnection
(Convert.ToString(_connectionstrings.DatabaseConnection)))
{
var parameter = new DynamicParameters();
parameter.Add("@ServiceID", ServiceID);
parameter.Add("@UserID", UserID);
var apimanagervm = con.Query<APIManagerVM>
("Usp_GetApiDetailsbyServiceIDandUserID", parameter, null,
false, 0, System.Data.CommandType.StoredProcedure).SingleOrDefault();
if(apimanagervm ==null)
{
return new APIManagerVM();
}
else
{
return apimanagervm;
}
}
}
catch (Exception)
{
throw;
}
}
public int DeactivateService(int? ServiceID, int? UserID)
{
try
{
using (SqlConnection con = new SqlConnection
(Convert.ToString(_connectionstrings.DatabaseConnection)))
{
var parameter = new DynamicParameters();
parameter.Add("@ServiceID", ServiceID);
parameter.Add("@UserID", UserID);
return con.Execute("Usp_DeactivateService_update",
parameter, null, 0, System.Data.CommandType.StoredProcedure);
}
}
catch (Exception)
{
throw;
}
}
public int ReactivateService(int? ServiceID, int? UserID)
{
try
{
using (SqlConnection con = new SqlConnection
(Convert.ToString(_connectionstrings.DatabaseConnection)))
{
var parameter = new DynamicParameters();
parameter.Add("@ServiceID", ServiceID);
parameter.Add("@UserID", UserID);
return con.Execute("Usp_ReactivateService_update",
parameter, null, 0, System.Data.CommandType.StoredProcedure);
}
}
catch (Exception)
{
throw;
}
}
}
}
存储库快照
完成添加生成、验证和保存 API 密钥所需的所有接口和具体类后,接下来我们将添加 ApplicationKeys
控制器。
添加 ApplicationKeysController
在此控制器中,我们将添加两个名为“GenerateKeys
”的动作方法,一个用于处理 [HttpGet
] 请求,另一个用于处理 [HttpPost
] 请求。
在 [HttpGet
] GenerateKeys
方法中,我们将把 ListServices
和 ListHits
的值赋给 GenerateKeysVM
视图模型,并将该模型发送到视图以绑定下拉列表。
在 [HttpPost
] GenerateKeys
方法中,我们将获取用户选择的 Service
和 Hits
的值。接下来,我们将根据数据库验证 Service
和 Hits
值,并检查此服务是否已订阅,如果是,我们将显示警告消息“所选服务已生成 API 密钥”。如果服务尚未订阅,我们将为该服务生成唯一的 API 密钥。
ApplicationKeysController 的代码片段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Repository;
using MoviesAPIStore.Models;
using MoviesAPIStore.AES256Encryption;
using Microsoft.AspNetCore.Http;
using MoviesAPIStore.Filters;
using Newtonsoft.Json;
// For more information on enabling MVC for empty projects,
// visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace MoviesAPIStore.Controllers
{
[ValidateUserSession]
public class ApplicationKeysController : Controller
{
IServicesStore _IServicesStore;
IHits _IHits;
IAPIManager _IAPIManager;
public ApplicationKeysController
(IServicesStore IServicesStore, IHits IHits, IAPIManager IAPIManager)
{
_IServicesStore = IServicesStore;
_IHits = IHits;
_IAPIManager = IAPIManager;
}
[HttpGet]
// GET: /<controller>/
public IActionResult GenerateKeys()
{
try
{
GenerateKeysVM generateKeysVM = new GenerateKeysVM();
generateKeysVM.ListServices = _IServicesStore.GetServiceList();
generateKeysVM.ListHits = _IHits.GetHitsList();
return View(generateKeysVM);
}
catch (Exception)
{
throw;
}
}
[HttpPost]
public IActionResult GenerateKeys(GenerateKeysVM generateKeysVM)
{
if (ModelState.IsValid)
{
var userID = Convert.ToInt32(HttpContext.Session.GetString("UserID"));
if (_IAPIManager.isApikeyAlreadyGenerated
(generateKeysVM.ServiceID, userID) > 0)
{
ModelState.AddModelError("",
"Api Key for Choosen Service is Already Generated");
generateKeysVM.ListServices = _IServicesStore.GetServiceList();
generateKeysVM.ListHits = _IHits.GetHitsList();
return View(generateKeysVM);
}
generateKeysVM.ListServices = _IServicesStore.GetServiceList();
generateKeysVM.ListHits = _IHits.GetHitsList();
if (GenerateKey(generateKeysVM) == 1)
{
TempData["APIKeyGeneratedMessage"] = "Done";
}
else
{
TempData["APIKeyGeneratedMessage"] = "Failed";
}
return View(generateKeysVM);
}
generateKeysVM.ListServices = _IServicesStore.GetServiceList();
generateKeysVM.ListHits = _IHits.GetHitsList();
return View(generateKeysVM);
}
[NonAction]
public int GenerateKey(GenerateKeysVM GenerateKeysVM)
{
try
{
APIManagerTB aPIManagerTB = new APIManagerTB()
{
APIKey = EncryptionLibrary.KeyGenerator.GetUniqueKey(),
HitsID = GenerateKeysVM.HitsID,
CreatedOn = DateTime.Now,
ServiceID = GenerateKeysVM.ServiceID,
UserID = Convert.ToInt32(HttpContext.Session.GetString("UserID")),
Status = "A"
};
return _IAPIManager.GenerateandSaveToken(aPIManagerTB);
}
catch (Exception)
{
throw;
}
}
public IActionResult DeactivateService(string ServiceID)
{
try
{
var result = _IAPIManager.DeactivateService
(Convert.ToInt32(ServiceID),
Convert.ToInt32(HttpContext.Session.GetString("UserID")));
return Json(data: result);
}
catch (Exception)
{
throw;
}
}
public IActionResult ReActivateService(string ServiceID)
{
try
{
var result = _IAPIManager.ReactivateService
(Convert.ToInt32(ServiceID),
Convert.ToInt32(HttpContext.Session.GetString("UserID")));
return Json(data: result);
}
catch (Exception)
{
throw;
}
}
}
}
理解了 ApplicationKeysController
的工作原理后,接下来我们看看如何生成唯一的 APIKey
并将其插入数据库。
GenerateKey 的代码片段
[NonAction]
public int GenerateKey(GenerateKeysVM GenerateKeysVM)
{
try
{
APIManagerTB aPIManagerTB = new APIManagerTB()
{
APIKey = EncryptionLibrary.KeyGenerator.GetUniqueKey(),
HitsID = GenerateKeysVM.HitsID,
CreatedOn = DateTime.Now,
ServiceID = GenerateKeysVM.ServiceID,
UserID = Convert.ToInt32(HttpContext.Session.GetString("UserID")),
Status = "A"
};
return _IAPIManager.GenerateandSaveToken(aPIManagerTB);
}
catch (Exception)
{
throw;
}
}
接下来,我们将添加 GenerateKeys
视图,并在其上添加两个下拉列表和一个按钮。
GenerateKey 的快照
接下来,要生成密钥,我们将选择服务和最大请求数,然后点击“创建 API 密钥”按钮来生成密钥。
生成 API 密钥后的 APIManager 表视图
生成密钥后,接下来我们将添加一个 ServicesStore Controller,它将显示所有服务。点击该服务后,您可以看到该服务的 API 密钥。
添加 ServicesStore 控制器
此控制器中有两个操作方法。两者都是 [HttpGet
] 方法,一个用于在视图上显示服务(Service
),另一个用于显示该服务的详细信息(Details
)。
ServicesStore 控制器的代码片段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Repository;
using MoviesAPIStore.Filters;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using MoviesAPIStore.Models;
// For more information on enabling MVC for empty projects,
// visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace MoviesAPIStore.Controllers
{
[ValidateUserSession]
public class ServicesStoreController : Controller
{
IServicesStore _IServicesStore;
IAPIManager _iAPIManager;
public ServicesStoreController
(IServicesStore IServicesStore, IAPIManager iAPIManager)
{
_IServicesStore = IServicesStore;
_iAPIManager = iAPIManager;
}
// GET: /<controller>/
public IActionResult Service()
{
return View(_IServicesStore.GetServiceListforDashboard());
}
public IActionResult Details(string ServiceID, string ServiceName)
{
try
{
var userID = Convert.ToInt32(HttpContext.Session.GetString("UserID"));
var apiDetails = _iAPIManager.GetApiDetailsbyServiceIDandUserID
(Convert.ToInt32(ServiceID), userID);
return View(apiDetails);
}
catch (Exception)
{
throw;
}
}
}
}
Service.cshtml 视图
@model List<MoviesAPIStore.Models.ServicesTB>
@{
Layout = "~/Views/Shared/_LayoutDashboard.cshtml";
}
<h2>Services</h2>
<div class="row">
@foreach (var service in Model)
{
<div class="col-sm-4">
<div class="card">
<div class="content">
<div class="row">
<div class="col-xs-5">
<div class="icon-big icon-info text-center">
<i class="ti-settings-alt"></i>
</div>
</div>
<div class="col-xs-7">
<div class="numbers">
@service.ServiceName API
</div>
</div>
</div>
<div class="footer">
<hr />
<div class="stats">
<i class="ti-reload"></i>
<a target="_blank"
href="/ServicesStore/Details/@service.ServiceID/
@service.ServiceName">Service Link</a>
</div>
</div>
</div>
</div>
</div>
}
</div>
服务视图快照
现在点击电影 API 服务链接,您可以看到服务详情视图以及其 API 密钥。
在这里,您可以通过点击 停用 按钮来选择停用和重新激活服务。
停用服务后的快照
重新激活服务后的快照
完成添加服务控制器以及激活和停用服务后,接下来我们将创建 Movies
API。
添加电影 API
在这部分,在添加 Web API 控制器之前,我们将添加接口和具体类来从数据库获取数据。
添加 IMovies 接口
IMovie
接口内部包含一个方法 GetMoviesStore
,它将返回一个 Movies
列表。
IMovies 接口的代码片段
using MoviesAPIStore.Models;
using System.Collections.Generic;
namespace MoviesAPIStore.Repository
{
public interface IMovies
{
List<MoviesTB> GetMoviesStore();
}
}
添加 MoviesConcrete 类
Movies
具体类实现 IMovie
接口。
MoviesConcrete 类的代码片段
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MoviesAPIStore.Repository
{
public class MoviesConcrete : IMovies
{
private DatabaseContext _context;
public MoviesConcrete(DatabaseContext context)
{
_context = context;
}
// GET: api/LatestMovies
public List<MoviesTB> GetMoviesStore()
{
try
{
var listofMovies = _context.MoviesTB.ToList();
return listofMovies;
}
catch (System.Exception)
{
throw;
}
}
}
}
添加电影控制器
在这部分,我们将添加一个名为“MoviesAPIController
”的 Web API 控制器,该控制器将返回 Movies
列表。我们只实现了 POST
方法。
代码片段
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Models;
using MoviesAPIStore.Repository;
using System.Collections.Generic;
namespace MoviesAPIStore.Controllers
{
[Route("api/[controller]")]
public class MoviesAPIController : Controller
{
IMovies _IMovies;
public MoviesAPIController(IMovies IMovies)
{
_IMovies = IMovies;
}
// POST api/values
[HttpPost]
public List<MoviesTB> Post([FromQuery]string key)
{
return _IMovies.GetMoviesStore();
}
}
}
同样,我们将添加 Music
API。
完成添加 Movies
和 Music
API 后,接下来我们将添加 Swagger 进行 API 文档。
向应用程序添加 Swagger 以进行 API 文档
什么是 Swagger?
Swagger 允许您描述 API 的结构,以便机器可以读取它们。
API 描述自身结构的能力是 Swagger 所有卓越之处的根源。为什么它如此出色?通过读取 API 的结构,我们可以自动构建美观且交互式的 API 文档。我们还可以自动生成多种语言的 API 客户端库,并探索自动化测试等其他可能性。
参考:https://swagger.org.cn/docs/specification/2-0/what-is-swagger/
要将 Swagger 添加到项目中,只需右键单击 Movies
API store 项目,然后从列表中选择“管理 NuGet 包”,将弹出一个 NuGet 新窗口。在其中,选择浏览选项卡并搜索“Swashbuckle.AspNetCore
”,然后单击 安装 按钮安装 Swagger。
添加 Swagger 后,我们需要向 startup.cs 类添加一些 Swagger 中间件才能使其正常工作。
以下是 startup
类的快照,其中我们注册并添加了 swagger 中间件。
现在让我们保存应用程序并运行以查看 API 文档。
要访问 Swagger,只需在 localhost 端口后输入“/swagger
”。
Swagger UI
哇,我们刚刚配置了它,没有编写任何设计和文档的代码。
电影 API 的 API 文档
音乐 API 的 API 文档
现在我们已经查看了两个 API 的文档。接下来,让我们通过创建中间件来验证 API 请求。
API 请求认证机制
在此过程中,我们已向用户(客户端)提供了 API 密钥,现在我们在创建 API 认证机制时,我们将验证来自客户端的每个请求,并且每个请求都必须包含我们提供的 API 密钥,以便我们可以根据数据库验证 API 密钥,并检查用户是否有权访问此服务。如果 API 密钥有效,用户将收到 API 的响应。如果请求无效,用户将收到有关请求中缺少内容的错误消息。
我们在此过程中添加了一个新功能,即我们可以激活和停用我们的服务,如果用户停用服务然后尝试访问服务,他将收到错误消息“服务已停用”。
下一个重点是此 API 应用程序中我们有最大请求限制,如果用户订阅了 1000 个请求,并且他尝试访问 API 超过 1000 个请求,他将收到错误消息“请求限制已超过”。
最后一种情况是用户可能订阅了两种服务,他将 Movies
API 密钥发送到 Music
API 请求,反之亦然,那么他将收到错误消息“无效用户密钥”。
如果请求有效,我们将发送电影集合作为响应。
到目前为止,我们已经完成了 API 及其文档的添加,现在让我们来编写此应用程序的主要过程,即用于验证请求的中间件。
让我们从添加名为 IValidateRequest
的接口并在其中声明方法开始。
添加 IValidateRequest 接口
namespace MoviesAPIStore.Repository
{
public interface IValidateRequest
{
bool ValidateKeys(string Key);
bool IsValidServiceRequest(string Key, string ServiceName);
bool ValidateIsServiceActive(string Key);
bool CalculateCountofRequest(string Key);
}
}
我们在 IValidateRequest
接口中声明了四个方法。
ValidateKeys
在此方法中,我们将以 API 密钥作为输入,并检查此密钥是否存在于数据库中。
IsValidServiceRequest
在此方法中,我们将检查 API 密钥是否已发送到有效的 API。为此,我们以密钥和服务名称(API 名称)作为输入。
例如,对于
Music
API,开发者不能发送Movies
API 密钥。ValidateIsServiceActive
在此方法中,我们以 API 密钥作为输入,并根据数据库检查此服务是活动还是停用。
CalculateCountofRequest
在此方法中,我们将以 API 密钥作为输入,并检查此 API 密钥的请求计数。
例如,如果用户已订阅 1000 个请求服务,并且他超出了限制。
添加 ValidateRequest 具体类
在这部分,我们将添加一个名为 ValidateRequestConcrete
的 Concrete
类,该类将继承 IValidateRequest
接口并实现其中的所有方法。
ValidateRequest Concrete 类的代码片段
using Microsoft.EntityFrameworkCore;
using MoviesAPIStore.MoviesContext;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MoviesAPIStore.Repository
{
public class ValidateRequestConcrete : IValidateRequest
{
private DatabaseContext _context;
public ValidateRequestConcrete(DatabaseContext context)
{
_context = context;
}
public bool ValidateKeys(string Key)
{
try
{
var result = (from apimanagertb in _context.APIManagerTB
where EF.Functions.Like(apimanagertb.APIKey, "%" + Key + "%")
select apimanagertb).Count();
if (result > 0)
{
return true;
}
else
{
return false;
}
}
catch (Exception)
{
throw;
}
}
public bool IsValidServiceRequest(string Key ,string ServiceName)
{
try
{
var serviceID = (from apimanagertb in _context.APIManagerTB
where EF.Functions.Like(apimanagertb.APIKey, "%" + Key + "%")
select apimanagertb.ServiceID).FirstOrDefault();
var serviceName = (from servicestb in _context.ServicesTB
where servicestb.ServiceID == serviceID
select servicestb.APIName).FirstOrDefault();
if (string.Equals(ServiceName, serviceName,
StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
else
{
return false;
}
}
catch (Exception)
{
throw;
}
}
public bool ValidateIsServiceActive(string Key)
{
try
{
var result = (from apimanagertb in _context.APIManagerTB
where EF.Functions.Like(apimanagertb.APIKey, "%" + Key + "%")
&& apimanagertb.Status == "A"
select apimanagertb).Count();
if (result > 0)
{
return true;
}
else
{
return false;
}
}
catch (Exception)
{
throw;
}
}
public bool CalculateCountofRequest(string Key)
{
try
{
var totalRequestCount = (from apimanagertb in _context.APIManagerTB
join hittb in _context.HitsTB on
apimanagertb.HitsID equals hittb.HitsID
where apimanagertb.APIKey == Key
select hittb.Hits).FirstOrDefault();
var totalCurrentRequestCount = (from loggertb in _context.LoggerTB
where loggertb.APIKey == Key
select loggertb).Count();
if (totalCurrentRequestCount >= totalRequestCount)
{
return false;
}
else
{
return true;
}
}
catch (Exception)
{
throw;
}
}
}
}
添加接口 IValidateRequest 和 ValidateRequestConcrete 后的快照
添加中间件以验证 API 请求
在开始此过程之前,让我们了解一下为什么需要中间件。如果我们在 ASP.NET MVC 中创建一个简单的应用程序,为了验证请求 API,我们使用 DelegatingHandler
。现在在 ASP.NET Core 中,它已被中间件取代。
什么是中间件?
中间件是组装到应用程序管道中以处理请求和响应的软件。
参考:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?tabs=aspnetcore2x
让我们从添加中间件开始。
注意:添加中间件,只需右键单击 Middlewares 文件夹,然后选择 -> 添加 -> 新项 - 将弹出一个名为 添加新项 的新对话框,在其中选择“ASP.NET Core” -> “Web”,然后在模板列表中,您会找到“中间件类”,只需选择它即可。
要添加中间件,我们将在应用程序中创建一个 Middlewares 文件夹。在此文件夹中,我们将添加一个名为“ApiKeyValidatorsMiddleware
”的中间件。
ApiKeyValidatorsMiddleware 的代码片段
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using MoviesAPIStore.Models;
using MoviesAPIStore.Repository;
using System;
using System.Threading.Tasks;
namespace MoviesAPIStore.Middlewares
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package
// into your project
public class ApiKeyValidatorsMiddleware
{
private readonly RequestDelegate _next;
IValidateRequest _IValidateRequest { get; set; }
IRequestLogger _IRequestLogger { get; set; }
public ApiKeyValidatorsMiddleware(RequestDelegate next,
IValidateRequest ivalidaterequest, IRequestLogger irequestlogger)
{
_next = next;
_IValidateRequest = ivalidaterequest;
_IRequestLogger = irequestlogger;
}
public async Task Invoke(HttpContext httpContext)
{
try
{
var remoteIpAddress = httpContext.Connection.RemoteIpAddress;
if (httpContext.Request.Path.StartsWithSegments("/api"))
{
var queryString = httpContext.Request.Query;
StringValues keyvalue;
queryString.TryGetValue("key", out keyvalue);
if (httpContext.Request.Method != "POST")
{
httpContext.Response.StatusCode = 405; //Method Not Allowed
await httpContext.Response.WriteAsync("Method Not Allowed");
return;
}
if (keyvalue.Count == 0)
{
httpContext.Response.StatusCode = 400; //Bad Request
await httpContext.Response.WriteAsync("API Key is missing");
return;
}
else
{
string[] serviceName = httpContext.Request.Path.Value.Split('/');
if(!_IValidateRequest.IsValidServiceRequest(keyvalue, serviceName[2]))
{
httpContext.Response.StatusCode = 401; //UnAuthorized
await httpContext.Response.WriteAsync
("Invalid User Key or Request");
return;
}
else if (!_IValidateRequest.ValidateKeys(keyvalue))
{
httpContext.Response.StatusCode = 401; //UnAuthorized
await httpContext.Response.WriteAsync("Invalid User Key");
return;
}
else if (!_IValidateRequest.ValidateIsServiceActive(keyvalue))
{
httpContext.Response.StatusCode = 406; //NotAcceptable
await httpContext.Response.WriteAsync("Service is Deactived");
return;
}
else if (!_IValidateRequest.CalculateCountofRequest(keyvalue))
{
httpContext.Response.StatusCode = 406; //NotAcceptable
await httpContext.Response.WriteAsync("Request Limit Exceeded");
return;
}
else
{
string[] apiName = httpContext.Request.Path.Value.Split('/');
var loggertb = new LoggerTB()
{
LoggerID = 0,
ContentType =
Convert.ToString(httpContext.Request.ContentType),
APIKey = keyvalue,
CreatedDate = DateTime.Now,
Host = httpContext.Request.Host.Value,
IsHttps = httpContext.Request.IsHttps ? "Yes" : "No",
Path = httpContext.Request.Path,
Method = httpContext.Request.Method,
Protocol = httpContext.Request.Protocol,
QueryString = httpContext.Request.QueryString.Value,
Scheme = httpContext.Request.Scheme,
RemoteIpAddress = Convert.ToString
(httpContext.Connection.RemoteIpAddress),
LoggerAPI = apiName[2],
};
_IRequestLogger.InsertLoggingData(loggertb);
}
}
}
await _next.Invoke(httpContext);
}
catch (Exception)
{
throw;
}
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ApiKeyValidatorsMiddleware>();
}
}
}
让我们了解中间件代码
在此中间件中,我们首先注入两个依赖项
IValidateRequest
IRequestLogger
IValidateRequest
接口包含所有 API 验证方法。
IRequestLogger
接口包含一个用于记录所有 API 请求的方法。
接下来,添加新中间件后,您将看到 Invoke
方法,我们将在其中编写整个验证过程。
- 我们验证的第一步是只验证 API 请求。
- 在第二步中,我们将只允许所有 API 的 POST 请求。如果是其他请求,我们将发送错误消息。
- 在第三步中,我们将检查查询字符串(“
Key
”)是否存在于请求 URI 中。 - 在第四步中,我们将检查用户在请求中发送的密钥以及他正在访问的 API 是否有效。例如,对于
Music
API,开发人员不发送Movies
API 密钥。 - 在第五步中,我们将检查用户发送的密钥是否有效。
- 在第六步中,我们将根据数据库检查 API 密钥,看此服务是激活还是停用。
- 在第七步中,我们将根据此 API 密钥检查 API 请求计数,如果超过限制,我们将向用户发送错误响应。
最后,如果请求通过所有障碍,则表示请求有效。
在 startup.cs 中注册中间件
现在,让我们在 startup.cs 类中注册此中间件,以便可以验证每个 API 请求。
现在,我们已经完成了“ApiKeyValidators
”中间件的添加和注册。现在让我们运行应用程序并检查中间件的工作方式。
访问最新电影 API 控制器
要访问 Movies
API,我们需要生成好的 API 密钥。
电影 API 密钥快照
现在我们将使用 POSTMAN APP
访问 Movies
API。
设置 POST 请求参数
要下载 Postman APP,请点击以下 URL
https://www.getpostman.com/postman
为 API 设置参数。
- URL:https://:50911/api/MoviesAPI?key=XtSREijsrZYkt9S
- API 名称:MoviesAPI
- API 密钥:XtSREijsrZYkt9S
- 请求类型:POST
发送有效密钥和请求后,我们得到了响应。
发送有效 API 请求后的响应
发送无效请求类型
我们向 Movies
API 发送了 Get
请求,它显示“方法不允许”,因为在中间件中,我们只允许所有 API 的 POST
请求。
发送无效密钥
我们在此请求中发送了一个无效的 API 密钥,以测试我们得到什么响应。
停用电影服务并发送请求
我们已经停用了 Movies
API 服务。让我们发送一个请求并测试我们得到什么响应。
我们得到的响应是正确的“服务已停用”。
发送超出订阅限额的请求
我们订阅了 1000 个请求,并且已经发送了完整的 1000 个请求。我尝试再次发送请求,然后它显示错误消息“请求限制已超出”。
存储所有 API 请求日志的表。
LoggerTB 表的快照
现在我们已经完成了安全部分。让我们看看仪表板。
最终项目结构
这是应用程序的最终项目结构。
在此部分中,我们可以看到一个用于存储 AES256 加密算法的文件夹,filters 文件夹包含用于验证用户会话的过滤器。Middleware 文件夹用于存储应用程序的所有中间件。而 repository 用于存储接口和具体类。
注意:我将 repository 文件夹保留在主应用程序中,因为这是一个小型演示应用程序。在大型应用程序中,您需要将其移动到单独的类库,同样,模型也需要这样做。
仪表板
在此仪表板上,您可以看到 API 的请求图表。对于 Movies
API,我们发送了 1000 个请求,因此它在图表上达到了峰值。
这些图表是根据每个请求中记录的数据显示的。
这些图表是 CHARTIST.JS。
仪表板快照
本项目中使用的工具
- c设计模板:Creative Tim 的 Paper Dashboard
- Swagger
- Dapper ORM
- chartist.js 图表
- 来自 https://www.flaticon.com/ 的图标
- AES256 加密
结论
在本文中,我们学习了 ASP.NET Core WEB API 中 API 开发的完整生命周期。我们从注册用户开始,然后生成了 API 密钥。此外,我们创建了 API,同时提供了激活和停用服务的功能,然后进入了验证 API 请求的主要过程,最后我们记录了每个请求,以便开发人员或普通用户知道用户请求 API 的次数。
感谢您的阅读。希望您喜欢我的文章。
历史
- 2018年2月6日:初始版本