Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Рассмотрев теоретические основы применения токена, теперь используем концепцию токенов в практическом примере.
Возьмем стандартный проект Web API с типом аутентификации Individual User Accounts. В нем по умолчанию есть контроллер AccountController, который содержит ряд методов, в том числе метод для регистрации:
[AllowAnonymous] [Route("Register")] public async Task<IHttpActionResult> Register(RegisterBindingModel model) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var user = new ApplicationUser() { UserName = model.Email, Email = model.Email }; IdentityResult result = await UserManager.CreateAsync(user, model.Password); if (!result.Succeeded) { return GetErrorResult(result); } return Ok(); }
Если переданные данные проходят валидацию, то методом UserManager.CreateAsync()
создается и добавляется в базу данных новый пользователь.
Метод регистрации у нас есть, но по умолчанию нет никакой формы html. Поэтому изменим код представления Index.cshtml следующим образом:
<div> <label>Введите email</label><br /> <input type="email" id="email" /> <br /><br /> <label>Введите пароль</label><br /> <input type="password" id="password" /><br /><br /> <label>Подтвердите пароль</label><br /> <input type="password" id="confirmpassword" /><br /><br /> <input type="submit" id="submit" value="Регистрация" /> </div> @section scripts{ <script type="text/javascript"> $(function () { $('#submit').click(function (e) { e.preventDefault(); var data = { Email: $('#email').val(), Password: $('#password').val(), ConfirmPassword: $('#confirmpassword').val() }; $.ajax({ type: 'POST', url: '/api/Account/Register', contentType: 'application/json; charset=utf-8', data: JSON.stringify(data) }).success(function (data) { alert("Регистрация пройдена"); }).fail(function (data) { alert("В процесе регистрации возникла ошибка"); }); }); }) </script> }
После успешной регистрации данные попадают в базу данных в таблицу AspNetUsers. Теперь нам надо войти на сайт. В отличие от ASP.NET MVC здесь нет традиционного логина. Вся суть логина в данном случае будет заключаться в получении токена, который даст нам доступ к ресурсам сайта. Для этого в представление Index.cshtml добавим специальный блок для входа на сайт:
<div class="userInfo" style="display:none;"> <p>Вы вошли как: <span class="userName"></span></p> <input type="button" value="Выйти" id="logOut" /> </div> <div class="loginForm"> <h3>Вход на сайт</h3> <label>Введите email</label><br /> <input type="email" id="emailLogin" /> <br /><br /> <label>Введите пароль</label><br /> <input type="password" id="passwordLogin" /><br /><br /> <input type="submit" id="submitLogin" value="Логин" /> </div> @section scripts{ <script type="text/javascript"> $(function () { //........................... var tokenKey = "tokenInfo"; $('#submitLogin').click(function (e) { e.preventDefault(); var loginData = { grant_type: 'password', username: $('#emailLogin').val(), password: $('#passwordLogin').val() }; $.ajax({ type: 'POST', url: '/Token', data: loginData }).success(function (data) { $('.userName').text(data.userName); $('.userInfo').css('display', 'block'); $('.loginForm').css('display', 'none'); // сохраняем в хранилище sessionStorage токен доступа sessionStorage.setItem(tokenKey, data.access_token); console.log(data.access_token); }).fail(function (data) { alert('При логине возникла ошибка'); }); }); $('#logOut').click(function (e) { e.preventDefault(); sessionStorage.removeItem(tokenKey); }); }) </script> }
Я добавил два блока. Первый невидимый для вывода информации о вошедшем пользователе и ссылкой выхода. Второй - собственно для логина.
По нажатию формируется js-объект:
var loginData = { grant_type: 'password', username: $('#emailLogin').val(), password: $('#passwordLogin').val() };
Он будет отправляться методом POST на адрес '/Token'. Поскольку за обработку запросов по этому маршруту отвечает провайдер авторизации, то данные запроса будут обрабатываться методом GrantResourceOwnerCredentials(), по результатам работы которого будет формироваться токен.
Ответом сервера в случае удачной аутентификации будет примерно следующий объект:
{ access_token: "u3XOCYV91f2P6odbceNIY_BnkfSpN7gQwzknsRi_.......0iRPlHYNMEES9", token_type: "bearer", expires_in: 1209599, userName: "metanit22@mail.ru", .issued: "Sat, 07 Mar 2015 21:42:16 GMT", .expires: "Sat, 21 Mar 2015 21:42:16 GMT" }
Параметр access_token
как раз и будет представлять токен доступа. Также в объекте передается дополнительная информация о периоде действия токена,
нике пользователя и тип токена.
Для того, чтобы в коде js данный токен в дальнейшем был доступен, то он сохраняется в хранилище sessionStorage.
По умолчанию в проекте Web API уже есть контроллер ValuesController с автосгенерированным кодом. Добавим в нему атрибут Authorize:
[Authorize] public class ValuesController : ApiController { public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } }
Добавим в представление Index.cshtml какой-либо функционал для оптравки запроса к методу get данного контроллера. Для целей тестирования я просто определю кнопку для отправки запроса и буду выводить полученный результат в всплывающем окне:
<div> <input type="submit" id="getItemsButton" value="Получить данные" /> </div> @section scripts{ <script type="text/javascript"> $(function () { var tokenKey = "tokenInfo"; //.................................. $('#getItemsButton').click(function (e) { e.preventDefault(); $.ajax({ type: 'GET', url: '/api/values/', beforeSend: function (xhr) { var token = sessionStorage.getItem(tokenKey); xhr.setRequestHeader("Authorization", "Bearer " + token); }, success: function (data) { alert(data); }, fail: function (data) { alert(data); } }); }); }) </script> }
Чтобы отправить токен, нам нужно настроить в запросе заголовок Authorization:
beforeSend: function (xhr) { var token = sessionStorage.getItem(tokenKey); xhr.setRequestHeader("Authorization", "Bearer " + token); }
По ранее сохраненному ключу получаем из хранилища sessionStorage токен и формируем заголовок.
Теперь после получения токена мы можем осуществить запрос к методу Get контроллера HomeController:
В то же время если мы попытаемся напрямую через запрос в адресной строке обратиться к этому методу, то у нас ничего не получится, так как мы не передали токен доступа: