Bu soruyu yanıtladım: 4 yıl önce HMAC kullanarak bir ASP.NET Web API'sinin güvenliği .
Şimdi, güvenlikte çok şey değişti, özellikle JWT popüler hale geliyor. Burada, JWT'yi mümkün olan en basit ve temel şekilde nasıl kullanacağımı açıklamaya çalışacağım, bu yüzden OWIN, Oauth2, ASP.NET Identity ormanından kaybolmayacağız ... :).
JWT jetonunu bilmiyorsanız, biraz şunlara bakmanız gerekir:
https://tools.ietf.org/html/rfc7519
Temel olarak, bir JWT jetonu şuna benzer:
<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>
Misal:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1NzI0LCJleHAiOjE0Nzc1NjY5MjQsImlhdCI6MTQ3NzU2NTcyNH0.6MzD1VwA5AcOcajkFyKhLYybr3h13iZjDyHm9zysDFQ
Bir JWT belirtecinin üç bölümü vardır:
- Üstbilgi: Base64 olarak kodlanan JSON biçimi
- Talepler: Base64'te kodlanan JSON biçimi.
- İmza: Base64'te kodlanan Başlık ve Talepler temel alınarak oluşturulmuş ve imzalanmıştır.
Yukarıdaki jetonla jwt.io web sitesini kullanırsanız , jetonun kodunu çözebilir ve aşağıdaki gibi görebilirsiniz:
Teknik olarak JWT, başlıklarda imzalanan ve başlıklarda belirtilen güvenlik algoritmasıyla talep edilen imzayı kullanır (örnek: HMACSHA256). Bu nedenle, taleplerde hassas bilgiler depolarsanız JWT'nin HTTP'ler üzerinden aktarılması gerekir.
Şimdi, JWT kimlik doğrulamasını kullanmak için eski bir Web Api sisteminiz varsa gerçekten bir OWIN ara katman yazılımına ihtiyacınız yoktur. Basit konsept, JWT belirtecinin nasıl sağlanacağı ve istek geldiğinde belirtecin nasıl doğrulanacağıdır. Bu kadar.
Geri demo, JWT belirteç hafif tutmak için, sadece depolamak username
ve expiration time
JWT'de. Ancak bu şekilde, rol yetkilendirmesi yapmak istiyorsanız: roller .. gibi daha fazla bilgi eklemek için yeni yerel kimlik (temel) yeniden oluşturmanız gerekir. Ancak, JWT'ye daha fazla bilgi eklemek istiyorsanız, size kalmış: çok esnektir.
OWIN ara katman yazılımı kullanmak yerine, denetleyiciden gelen eylemi kullanarak bir JWT belirteç uç noktası sağlayabilirsiniz:
public class TokenController : ApiController
{
// This is naive endpoint for demo, it should use Basic authentication
// to provide token or POST request
[AllowAnonymous]
public string Get(string username, string password)
{
if (CheckUser(username, password))
{
return JwtManager.GenerateToken(username);
}
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
public bool CheckUser(string username, string password)
{
// should check in the database
return true;
}
}
Bu naif bir eylemdir; üretimde JWT belirteci sağlamak için bir POST isteği veya Temel Kimlik Doğrulama uç noktası kullanmalısınız.
Jeton nasıl oluşturulur username
?
Jetonu System.IdentityModel.Tokens.Jwt
oluşturmak için Microsoft'tan çağrılan NuGet paketini , hatta isterseniz başka bir paketi kullanabilirsiniz. Demoda aşağıdakilerle HMACSHA256
birlikte kullanıyorum SymmetricKey
:
/// <summary>
/// Use the below code to generate symmetric Secret Key
/// var hmac = new HMACSHA256();
/// var key = Convert.ToBase64String(hmac.Key);
/// </summary>
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";
public static string GenerateToken(string username, int expireMinutes = 20)
{
var symmetricKey = Convert.FromBase64String(Secret);
var tokenHandler = new JwtSecurityTokenHandler();
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
}),
Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(symmetricKey),
SecurityAlgorithms.HmacSha256Signature)
};
var stoken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(stoken);
return token;
}
JWT belirtecini sağlamak için uç nokta yapılır. Şimdi, istek geldiğinde JWT nasıl doğrulanır? Demoda
JwtAuthenticationAttribute
hangi miras aldım IAuthenticationFilter
( burada kimlik doğrulama filtresi hakkında daha fazla ayrıntı ).
Bu özellik ile, herhangi bir eylemin kimliğini doğrulayabilirsiniz: bu özelliği bu eyleme koymanız yeterlidir.
public class ValueController : ApiController
{
[JwtAuthentication]
public string Get()
{
return "value";
}
}
WebAPI'niz için gelen tüm istekleri doğrulamak istiyorsanız OWIN ara katman yazılımını veya DelegateHander'ı da kullanabilirsiniz (Denetleyici veya eyleme özgü değildir)
Kimlik doğrulama filtresinin temel yöntemi aşağıdadır:
private static bool ValidateToken(string token, out string username)
{
username = null;
var simplePrinciple = JwtManager.GetPrincipal(token);
var identity = simplePrinciple.Identity as ClaimsIdentity;
if (identity == null)
return false;
if (!identity.IsAuthenticated)
return false;
var usernameClaim = identity.FindFirst(ClaimTypes.Name);
username = usernameClaim?.Value;
if (string.IsNullOrEmpty(username))
return false;
// More validate to check whether username exists in system
return true;
}
protected Task<IPrincipal> AuthenticateJwtToken(string token)
{
string username;
if (ValidateToken(token, out username))
{
// based on username to get more information from database
// in order to build local identity
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
// Add more claims if needed: Roles, ...
};
var identity = new ClaimsIdentity(claims, "Jwt");
IPrincipal user = new ClaimsPrincipal(identity);
return Task.FromResult(user);
}
return Task.FromResult<IPrincipal>(null);
}
İş akışı, JWT jetonunu doğrulamak ve sonra geri dönmek için JWT kitaplığını (yukarıdaki NuGet paketi) kullanmaktır ClaimsPrincipal
. Kullanıcının sisteminizde var olup olmadığını kontrol etmek gibi daha fazla doğrulama gerçekleştirebilir ve isterseniz diğer özel doğrulamaları ekleyebilirsiniz. JWT jetonunu doğrulamak ve anapara geri almak için kod:
public static ClaimsPrincipal GetPrincipal(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
if (jwtToken == null)
return null;
var symmetricKey = Convert.FromBase64String(Secret);
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
return principal;
}
catch (Exception)
{
//should write log
return null;
}
}
JWT belirteci doğrulanırsa ve asıl iade edilirse, rol yetkilendirmesini denetlemek için yeni bir yerel kimlik oluşturmanız ve bu klasöre daha fazla bilgi girmeniz gerekir.
config.Filters.Add(new AuthorizeAttribute());
Kaynaklarınıza anonim bir istek gelmesini önlemek için genel kapsamda (varsayılan yetkilendirme) eklemeyi unutmayın .
Demoyu test etmek için Postacı'yı kullanabilirsiniz:
İstek jetonu (yukarıda belirttiğim gibi saf, sadece demo için):
GET http://localhost:{port}/api/token?username=cuong&password=1
Yetkili istek için başlığa JWT jetonu koyun, örnek:
GET http://localhost:{port}/api/value
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s
Demo buraya yerleştirilir: https://github.com/cuongle/WebApi.Jwt