JWT Authentication с .NET Core 2.1 и React

Какво точно представлява JWT (JSON Web Token)?
Няма да навлизаме във формални подробности, затова си има Wikipedia (виж тук). Все пак, най-важните неща, които трябва да знаем за JWT са:
- Съдържа определен брой твърдения (например „влязъл като админ“)
- Генерира се от сървъра и се подписва с частния ключ на едната страна (обикновено на сървъра)
- Когато потребителят получи този токен, той трябва да го запази локално, за да може по-късно да използва защитените ресурси
И така, за тази имплементация ще използваме .NET Core 2.1 и ReactJS.
За да си създадем примерен проект изпълняваме
dotnet new react -o <project_name>
в инструмента за текстови команди. (Първо се уверете, че .NET Core SDK е инсталиран на вашата машина.)
Генериране на токена
1. Добавяме
app.UseAuthentication()
в метода Configure в Startup.cs. Това добавя инстанция на AuthenticationMiddleware към последователността от действия при обработка на заявки от страна на процеса, което на практика включва възможността за автентикация.
2. В тялото на метода ConfigureServices добавяме
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { RequireExpirationTime = true, ValidIssuer = "YOU_ISSUER_VALUE", ValidateIssuer = true, ValidateAudience = false, ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_KEY")) }; });
Току-що казахме на нашия сървър какво да търси, когато валидира токен, а също така и ключа, с който ще бъде подписан всеки токен.
3. Вече сме готови да добавим нашият Controller метод, който всъщност ще създаде токените. Преди това, обаче, ще допълним
routes.MapRoute(name: "api",template:"api/{controller}/{action}/{id?}");
към извикването на метода UseMvc в Configure метода.
4. Сега нека създадем нов RegistrationController в проекта и да го добавим в login метода.
[HttpPost] public JsonResult Login([FromBody] LoginParameters login) { <Here we should validate the received email and password and proceed if they are valid> var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_KEY")); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(ClaimTypes.Role, "Administrator"), }; var token = new JwtSecurityToken("YOUR_ISSUER_VALUE", "YOUR_AUDIENCE_VALUE", claims, expires: DateTime.Now.AddMinutes(30),signingCredentials: creds); var tokenString = new JwtSecurityTokenHandler().WriteToken(token); return new JsonResult(new {token = tokenString });
Тук LoginParameters е клас, който има две полета – Email и Password.
Получаване и запаметяване на токена
Сега нека създадем нашия login формуляр. Първо ще добавя два npm пакета: Material-UI и Axios. Първият представлява много добра библиотека с React контроли, а вторият – Promise-based HTTP клиент. Те в никакъв случай не са задължителни, но аз обичам да ги използвам в моите React проекти.
За да ги инсталирате, отворете командния прозорец и изпълнете
npm install --save @material-ui/core axios
Ще създадем собствен HTTP клиент, който използва Axios библиотеката и нашето цяло приложение ще използва този клиент като bottleneck. На това място ще поставим токена, след като сме го получили.
import axios from 'axios' class httpClient { constructor() { const token = JSON.parse(localStorage.getItem('user') || '{}')['token'] const instance = axios.create({ baseURL: '/', headers: { 'Authorization': `Bearer ${token}` } }) this.axiosInstance = instance } get(url){ return this.axiosInstance.get(url) .then((resp) => { }) .catch((resp) => { if (resp.response !== undefined && resp.response.status == '401') { localStorage.removeItem('user') location.replace('/login') } else { return Promise.reject(resp) }}) } post(url, formData) { return this.axiosInstance.post(url, formData) .then((resp) => { }) .catch((resp) => { if (resp.response !== undefined && resp.response.status == '401') { localStorage.removeItem('user') location.replace('/login') } else { return Promise.reject(resp) }}) } setTokenOnLogin = () => { const token = JSON.parse(localStorage.getItem('user') || '{}')['token'] this.axiosInstance.defaults.headers = { 'Authorization': `Bearer ${token}` } } clearTokenOnLogout = () => { localStorage.removeItem('user') this.axiosInstance.defaults.headers = {} }} const instance = new httpClient() export default instance
Остана ни само да set-нем item с ключ ‘user’ и стойност – полученият токен, ако заявката до метода Login е била успешна.
Източник на текст и връзки
Можете да намерите повече информация тук: iphos.bg