我已经创建了一个Asp核心Web API,将由组织外部的C#控制台应用程序使用。该控制台应用程序计划定期运行。因此,在运行控制台应用程序时,Web api的点击率会很高。 请协助我如何保护我的Web Api免受恶意软件攻击或未经授权的访问。我无法使用AD身份验证,因为我无法在AAD(Azure活动目录)中注册客户端应用程序。
答案 0 :(得分:1)
通常来说,有很多方法可以做到这一点。例如,使用基本方案身份验证,其中客户端使用base64-encoding发送username:password
。但是。那不是那么安全。
我建议您使用JWT令牌。 Jwt方案的身份验证非常简单:
JWT
和client_id
的{{1}}令牌。 (您可以在服务器上的配置文件或数据库中配置它们)client_key
和client_id
匹配,则服务器会发送一个带有client_key
访问令牌的响应,如果您愿意,可以添加一个刷新令牌;否则,发送带有JWT
的响应。401
标头的webapi。服务器将对Authorization: Bearer ${access_token}
进行解密,并在有效时执行正确的操作。以下是详细操作方法:
为了表示控制台发送的access_token
和client_id
,我们创建一个虚拟Dto类:
client_key
在创建和验证Jwt令牌时,我们需要有关发行者,受众和秘密密钥的信息。为了保存这些信息,让我们创建另一个虚拟类:
public class AskForTokenRequest
{
public string ClientId { get; set; }
public string ClientKey { get; set; }
}
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);
}
}
添加到DI容器并添加JwtBearer身份验证方案
JwtTokenHelper
不要忘记在您的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();
}
方法中添加app.UseAuthentication();
。
现在,创建一个控制器以生成Jwt令牌
Configure()
并使用[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,
});
}
}
属性保护您的webapi:
[Authorize]