Регистрация, авторизация, получение и использование токена

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 29.10.2015

Рассмотрев теоретические основы применения токена, теперь используем концепцию токенов в практическом примере.

Возьмем стандартный проект 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>
    }
Регистрация в Web API

После успешной регистрации данные попадают в базу данных в таблицу 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:

Get Access Token in Web API

В то же время если мы попытаемся напрямую через запрос в адресной строке обратиться к этому методу, то у нас ничего не получится, так как мы не передали токен доступа:

Set Access Token in Web API
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850