控制台应用程序使用安全 Web Api

Secure Web Api to consumed by console Appplicatuion

我已经创建了一个 Asp 核心 Web api,它将被组织外部的 C# 控制台应用程序使用。此控制台应用程序计划定期 运行。因此,当控制台应用程序 运行 时,网络上的点击率 api 就会出现。 请帮助我如何保护我的网站 Api 免受恶意软件攻击或未经授权的访问。我无法使用 AD 身份验证,因为我无法在 AAD(Azure 活动目录)中注册客户端应用程序请协助。

一般来说,有很多方法可以做到这一点。例如,使用基本方案身份验证,其中客户端发送带有 base64 编码的 username:password。然而 。没那么安全。

我建议你使用 JWT 令牌。 Jwt方案的认证非常简单:

  1. 客户端发送请求,要求使用 client_idclient_key 获取 JWT 令牌。 (您可以在服务器上的配置文件或数据库中配置它们)
  2. 如果 client_idclient_key 匹配,服务器会发送一个带有 JWT 访问令牌的响应,如果您愿意,还可以发送一个额外的刷新令牌;否则,发送带有 401.
  3. 的响应
  4. 客户端使用 Authorization: Bearer ${access_token} header 的 webapi。服务器将解密 access_token 并在有效时执行正确的操作。

这里有一个how-to的详细信息:

  1. 用于保存信息的虚拟 class

为了表示您的控制台发送的 client_idclient_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 = "!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!!!@#$%^&*()&!";
}
  1. 在我们继续之前,让我们创建一个 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);
    }

}
  1. 配置服务器以启用 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();

  1. 使用方法:

现在,创建一个控制器来生成 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
        });                
    }
}