控制台应用程序使用安全 Web Api
Secure Web Api to consumed by console Appplicatuion
我已经创建了一个 Asp 核心 Web api,它将被组织外部的 C# 控制台应用程序使用。此控制台应用程序计划定期 运行。因此,当控制台应用程序 运行 时,网络上的点击率 api 就会出现。
请帮助我如何保护我的网站 Api 免受恶意软件攻击或未经授权的访问。我无法使用 AD 身份验证,因为我无法在 AAD(Azure 活动目录)中注册客户端应用程序请协助。
一般来说,有很多方法可以做到这一点。例如,使用基本方案身份验证,其中客户端发送带有 base64 编码的 username:password
。然而 。没那么安全。
我建议你使用 JWT 令牌。 Jwt方案的认证非常简单:
- 客户端发送请求,要求使用
client_id
和 client_key
获取 JWT
令牌。 (您可以在服务器上的配置文件或数据库中配置它们)
- 如果
client_id
和 client_key
匹配,服务器会发送一个带有 JWT
访问令牌的响应,如果您愿意,还可以发送一个额外的刷新令牌;否则,发送带有 401
. 的响应
- 客户端使用
Authorization: Bearer ${access_token}
header 的 webapi。服务器将解密 access_token
并在有效时执行正确的操作。
这里有一个how-to的详细信息:
- 用于保存信息的虚拟 class
为了表示您的控制台发送的 client_id
和 client_key
,让我们创建一个虚拟 Dto class :
public class AskForTokenRequest
{
public string ClientId { get; set; }
public string ClientKey { get; set; }
}
在创建和验证 Jwt 令牌时,我们需要有关颁发者、受众和密钥的信息。为了保存这些信息,让我们创建另一个虚拟 class :
public class SecurityInfo {
public static readonly string Issuer = "xxx";
public static readonly string[] Audiences = new[] { "yyy" };
public static readonly string SecretKey = "!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!";
}
- 在我们继续之前,让我们创建一个
JwtTokenHelper
来生成令牌:
JwtTokenHelper
有助于验证 client_id
& client_key
并生成 Jwt
令牌。
public class JwtTokenHelper
{
//private AppDbContext _dbContext { get; set; }
//public JwtTokenHelper(AppDbContext dbContext) {
// this._dbContext = dbContext;
//}
public virtual bool ValidateClient(string clientId, string clientKey)
{
// check the client_id & clientKey with database , config file , or sth else
if (clientId == "your_console_client_id" && clientKey == "your_console_client_key")
return true;
return false;
}
/// construct a token
public virtual JwtSecurityToken GenerateToken(string clientId, DateTime expiry, string audience)
{
ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(clientId, "jwt"));
var token=new JwtSecurityToken
(
claims: identity.Claims,
issuer: SecurityInfo.Issuer,
audience: audience,
expires: expiry,
notBefore: DateTime.UtcNow,
signingCredentials: new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityInfo.SecretKey)),
SecurityAlgorithms.HmacSha256
)
);
return token;
}
public virtual string GenerateTokenString(string clientId, DateTime expiry,string audience)
{
// construct a jwt token
var token = GenerateToken(clientId,expiry,audience);
// convert the token to string
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.WriteToken(token);
}
}
- 配置服务器以启用 JwtBearer 身份验证:
添加JwtTokenHelper
到DI容器和添加JwtBearer的认证方案
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<JwtTokenHelper>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = SecurityInfo.Issuer,
ValidAudiences = SecurityInfo.Audiences,
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = new List<SecurityKey> {
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityInfo.SecretKey) )
},
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(60)
};
});
services.AddMvc();
}
不要忘记在您的 Configure()
方法中添加 app.UseAuthentication();
。
- 使用方法:
现在,创建一个控制器来生成 Jwt 令牌
[Route("/api/token")]
public class TokenController : Controller
{
private readonly JwtTokenHelper _tokenHelper;
public TokenController(JwtTokenHelper tokenHelper) {
this._tokenHelper = tokenHelper;
}
[HttpPost]
public IActionResult Create([FromBody] AskForTokenRequest client)
{
if(! this._tokenHelper.ValidateClient(client.ClientId , client.ClientKey))
return new StatusCodeResult(401);
DateTime expiry = DateTime.UtcNow.AddMinutes(60); // expires in 1 hour
var audience = "yyy";
var access_token = this._tokenHelper.GenerateTokenString(client.ClientKey, expiry,audience);
return new JsonResult(new {
access_token = access_token,
});
}
}
并使用 [Authorize]
属性保护您的 webapi :
public class HomeController : Controller
{
[Authorize]
public IActionResult GetYourWebApiMethod(){
return new ObjectResult(new {
Username = User.Identity.Name
});
}
}
我已经创建了一个 Asp 核心 Web api,它将被组织外部的 C# 控制台应用程序使用。此控制台应用程序计划定期 运行。因此,当控制台应用程序 运行 时,网络上的点击率 api 就会出现。 请帮助我如何保护我的网站 Api 免受恶意软件攻击或未经授权的访问。我无法使用 AD 身份验证,因为我无法在 AAD(Azure 活动目录)中注册客户端应用程序请协助。
一般来说,有很多方法可以做到这一点。例如,使用基本方案身份验证,其中客户端发送带有 base64 编码的 username:password
。然而 。没那么安全。
我建议你使用 JWT 令牌。 Jwt方案的认证非常简单:
- 客户端发送请求,要求使用
client_id
和client_key
获取JWT
令牌。 (您可以在服务器上的配置文件或数据库中配置它们) - 如果
client_id
和client_key
匹配,服务器会发送一个带有JWT
访问令牌的响应,如果您愿意,还可以发送一个额外的刷新令牌;否则,发送带有401
. 的响应
- 客户端使用
Authorization: Bearer ${access_token}
header 的 webapi。服务器将解密access_token
并在有效时执行正确的操作。
这里有一个how-to的详细信息:
- 用于保存信息的虚拟 class
为了表示您的控制台发送的 client_id
和 client_key
,让我们创建一个虚拟 Dto class :
public class AskForTokenRequest
{
public string ClientId { get; set; }
public string ClientKey { get; set; }
}
在创建和验证 Jwt 令牌时,我们需要有关颁发者、受众和密钥的信息。为了保存这些信息,让我们创建另一个虚拟 class :
public class SecurityInfo {
public static readonly string Issuer = "xxx";
public static readonly string[] Audiences = new[] { "yyy" };
public static readonly string SecretKey = "!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!";
}
- 在我们继续之前,让我们创建一个
JwtTokenHelper
来生成令牌:
JwtTokenHelper
有助于验证 client_id
& client_key
并生成 Jwt
令牌。
public class JwtTokenHelper
{
//private AppDbContext _dbContext { get; set; }
//public JwtTokenHelper(AppDbContext dbContext) {
// this._dbContext = dbContext;
//}
public virtual bool ValidateClient(string clientId, string clientKey)
{
// check the client_id & clientKey with database , config file , or sth else
if (clientId == "your_console_client_id" && clientKey == "your_console_client_key")
return true;
return false;
}
/// construct a token
public virtual JwtSecurityToken GenerateToken(string clientId, DateTime expiry, string audience)
{
ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(clientId, "jwt"));
var token=new JwtSecurityToken
(
claims: identity.Claims,
issuer: SecurityInfo.Issuer,
audience: audience,
expires: expiry,
notBefore: DateTime.UtcNow,
signingCredentials: new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityInfo.SecretKey)),
SecurityAlgorithms.HmacSha256
)
);
return token;
}
public virtual string GenerateTokenString(string clientId, DateTime expiry,string audience)
{
// construct a jwt token
var token = GenerateToken(clientId,expiry,audience);
// convert the token to string
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.WriteToken(token);
}
}
- 配置服务器以启用 JwtBearer 身份验证:
添加JwtTokenHelper
到DI容器和添加JwtBearer的认证方案
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<JwtTokenHelper>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = SecurityInfo.Issuer,
ValidAudiences = SecurityInfo.Audiences,
ValidateAudience = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = new List<SecurityKey> {
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityInfo.SecretKey) )
},
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(60)
};
});
services.AddMvc();
}
不要忘记在您的 Configure()
方法中添加 app.UseAuthentication();
。
- 使用方法:
现在,创建一个控制器来生成 Jwt 令牌
[Route("/api/token")]
public class TokenController : Controller
{
private readonly JwtTokenHelper _tokenHelper;
public TokenController(JwtTokenHelper tokenHelper) {
this._tokenHelper = tokenHelper;
}
[HttpPost]
public IActionResult Create([FromBody] AskForTokenRequest client)
{
if(! this._tokenHelper.ValidateClient(client.ClientId , client.ClientKey))
return new StatusCodeResult(401);
DateTime expiry = DateTime.UtcNow.AddMinutes(60); // expires in 1 hour
var audience = "yyy";
var access_token = this._tokenHelper.GenerateTokenString(client.ClientKey, expiry,audience);
return new JsonResult(new {
access_token = access_token,
});
}
}
并使用 [Authorize]
属性保护您的 webapi :
public class HomeController : Controller
{
[Authorize]
public IActionResult GetYourWebApiMethod(){
return new ObjectResult(new {
Username = User.Identity.Name
});
}
}