मैंने इस सवाल का जवाब दिया: कैसे एक ASP.NET वेब एपीआई को 4 साल पहले एचएमएसी का उपयोग करके सुरक्षित किया जाए ।
अब, सुरक्षा में बहुत सारी चीजें बदल गईं, खासकर JWT लोकप्रिय हो रही है। यहाँ, मैं यह समझाने की कोशिश करूँगा कि JWT को सबसे सरल और बुनियादी तरीके से कैसे उपयोग किया जा सकता है, जिससे हम OWIN, Oauth2, ASP.NET आइडेंटिटी ... के जंगल से नहीं हटेंगे ... :)।
यदि आप JWT टोकन नहीं जानते हैं, तो आपको थोड़ा सा देखने की आवश्यकता है:
https://tools.ietf.org/html/rfc7519
मूल रूप से, JWT टोकन जैसा दिखता है:
<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>
उदाहरण:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1NzI0LCJleHAiOjE0Nzc1NjY5MjQsImlhdCI6MTQ3NzU2NTcyNH0.6MzD1VwA5AcOcajkFyKhLYybr3h13iZjDyHm9zysDFQ
JWT टोकन में तीन खंड होते हैं:
- हैडर: JSON प्रारूप जो कि बेस 64 में एन्कोड किया गया है
- दावे: JSON प्रारूप जो Base64 में एन्कोडेड है।
- हस्ताक्षर: हैडर और दावों के आधार पर बनाया और हस्ताक्षरित किया गया है जो बेस 64 में एन्कोडेड है।
यदि आप ऊपर टोकन के साथ वेबसाइट jwt.io का उपयोग करते हैं , तो आप टोकन को डीकोड कर सकते हैं और इसे नीचे देख सकते हैं:
तकनीकी रूप से, JWT हस्ताक्षर का उपयोग करता है जो हेडर से हस्ताक्षरित है और हेडर में निर्दिष्ट सुरक्षा एल्गोरिथ्म के साथ दावा करता है (उदाहरण: HMACSHA256)। इसलिए, यदि आप दावों में कोई संवेदनशील जानकारी संग्रहीत करते हैं, तो JWT को HTTP पर स्थानांतरित किया जाना आवश्यक है।
JWT प्रमाणीकरण का उपयोग करने के लिए, यदि आपके पास विरासत वेब एप प्रणाली है, तो आपको वास्तव में OWIN मिडलवेयर की आवश्यकता नहीं है। सरल अवधारणा यह है कि JWT टोकन कैसे प्रदान किया जाए और अनुरोध आने पर टोकन को कैसे मान्य किया जाए। बस।
डेमो में वापस, जेडब्ल्यूटी टोकन को हल्का रखने के लिए, मैं केवल स्टोर करता हूं username
और expiration time
जेडब्ल्यूटी में। लेकिन इस तरह, आपको और अधिक जानकारी जोड़ने के लिए नई स्थानीय पहचान (प्रिंसिपल) का निर्माण करना होगा: भूमिकाएँ .. यदि आप भूमिका प्राधिकरण करना चाहते हैं। लेकिन, यदि आप JWT में अधिक जानकारी जोड़ना चाहते हैं, तो यह आपके ऊपर है: यह बहुत लचीला है।
OWIN मिडलवेयर का उपयोग करने के बजाय, आप नियंत्रक से कार्रवाई का उपयोग करके केवल JWT टोकन समापन बिंदु प्रदान कर सकते हैं:
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;
}
}
यह एक भोली क्रिया है; उत्पादन में आपको JWT टोकन प्रदान करने के लिए एक POST अनुरोध या एक मूल प्रमाणीकरण समापन बिंदु का उपयोग करना चाहिए।
टोकन के आधार पर कैसे उत्पन्न करें username
?
System.IdentityModel.Tokens.Jwt
यदि आप चाहें तो टोकन बनाने के लिए आप Microsoft से बुलाए गए NuGet पैकेज या किसी अन्य पैकेज का उपयोग कर सकते हैं। डेमो में, मैं इसके HMACSHA256
साथ उपयोग करता हूं 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 टोकन प्रदान करने के लिए समापन बिंदु किया गया है। अब, अनुरोध आने पर JWT को कैसे मान्य किया जाए? डेमो में मैंने बनाया है
JwtAuthenticationAttribute
जो इनहेरिट करता है IAuthenticationFilter
(प्रमाणीकरण फिल्टर के बारे में अधिक विवरण यहां से )।
इस विशेषता के साथ, आप किसी भी कार्रवाई को प्रमाणित कर सकते हैं: आपको इस विशेषता को उस कार्रवाई पर रखना होगा।
public class ValueController : ApiController
{
[JwtAuthentication]
public string Get()
{
return "value";
}
}
यदि आप अपने WebAPI के लिए सभी आवक अनुरोधों को मान्य करना चाहते हैं (नियंत्रक या कार्रवाई के लिए विशिष्ट नहीं) तो आप OWIN मिडलवेयर या डेलिगेटहैंडर का उपयोग कर सकते हैं।
नीचे प्रमाणीकरण फिल्टर से मुख्य विधि है:
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);
}
JWT टोकन को मान्य करने और फिर वापस लौटने के लिए वर्कफ़्लो JWT लाइब्रेरी (उपरोक्त नूगेट पैकेज) का उपयोग कर रहा है ClaimsPrincipal
। आप यह जाँच सकते हैं कि उपयोगकर्ता आपके सिस्टम पर मौजूद है या नहीं और यदि आप चाहें तो अन्य कस्टम सत्यापन जोड़ सकते हैं। जेडब्ल्यूटी टोकन को मान्य करने और प्रिंसिपल वापस पाने के लिए कोड:
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 टोकन को मान्य किया गया है और मूलधन वापस आ गया है, तो आपको एक नई स्थानीय पहचान बनानी चाहिए और भूमिका प्राधिकरण की जांच करने के लिए इसमें और जानकारी डालनी चाहिए।
config.Filters.Add(new AuthorizeAttribute());
अपने संसाधनों के लिए किसी भी अनाम अनुरोध को रोकने के लिए वैश्विक दायरे में (डिफ़ॉल्ट प्राधिकरण) जोड़ना याद रखें ।
डेमो का परीक्षण करने के लिए आप पोस्टमैन का उपयोग कर सकते हैं:
टोकन का अनुरोध करें (जैसा कि मैंने ऊपर बताया है, बस डेमो के लिए):
GET http://localhost:{port}/api/token?username=cuong&password=1
अधिकृत अनुरोध के लिए हेडर में JWT टोकन डालें, उदाहरण:
GET http://localhost:{port}/api/value
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s
डेमो यहां डाला गया है: https://github.com/cuongle/WebApi.Jwt