Как сделать действия WebAPI доступными только из моего приложения?
Общим вариантом использования для WebAPI было бы иметь представления оболочки, отображаемые MVC-контроллерами, которые содержат javascript, который затем попадает в ваш API для доступа к данным.
Но скажем, что у вас есть некоторые дорогостоящие операции API, и вы не хотите, чтобы люди могли удаленно обращаться к этим конечным точкам - вам нужны только ваши просмотры MVC, предоставленные вашим приложением, для доступа к ним. Как вы могли защитить их?
В этом случае Request.IsLocal
не работает, потому что javascript вызывает его из браузера клиента на своей машине. Даже если это сработало, вам нужно копать, чтобы получить реальный HttpContext
, чтобы найти это свойство, - и это решение не будет работать в самообслуживании WebAPI.
Для конечных точек API, для которых требуется действительный IPrincipal
, вы можете защитить их с помощью атрибута [Authorize]
. Но как насчет конечных точек API, к которым вы хотите, чтобы ваше приложение было доступно для анонимных пользователей?
Я попробовал решение и опубликую его отдельно как ответ, потому что я не уверен, что это лучший (или даже хороший) подход.
Ответы
Ответ 1
Если ваш сайт MVC использует проверку подлинности, вы можете включить проверку подлинности на основе форм для ваших методов веб-API. Вы можете написать собственный атрибут [Authorize]
, который будет проверять наличие cookie проверки подлинности форм, который будет отправлен из вызова AJAX, и если он содержит конструкцию принципала.
Другим возможным решением является защита вашего API с помощью tokens
, который является более RESTful. Идея здесь заключается в том, что когда пользователь аутентифицируется на вашем веб-сайте MVC, вы можете сгенерировать и передать токен представлению, которое будет использоваться при отправке запроса AJAX в веб-API, который, в свою очередь, проверяет правильность токена и его подпись.
Если, с другой стороны, ваш сайт не использует аутентификацию, все будет очень сложно, потому что у вас нет способа узнать, поступает ли запрос от доверенного клиента, поскольку вы используете javascript для вызова ваших методов API.
Ответ 2
Прежде чем вы начнете обсуждать "что вы пробовали", вот что я пробовал. Оно работает. Просто не уверен, есть ли лучший способ.
-
Создайте фильтр действий MVC и добавьте его как глобальный фильтр во время Application_Start
.
-
Создайте фильтр действий Http (WebAPI) и используйте его для действий, которые должны отклонять удаленные запросы.
Глобальный фильтр MVC выполняет следующее:
-
Ищет конкретный файл cookie в запросе. Если файл cookie существует, его значение расшифровывается. Дешифрованное значение должно быть строковым представлением DateTime
, поэтому используйте DateTime.TryParse
, чтобы получить его. Если значение правильно проанализировано с помощью DateTime
и что DateTime
меньше одного дня, остановитесь здесь и ничего не делайте.
-
Если cookie не существует или не может быть дешифрован/разбор или старше одного дня, напишите в браузере новый файл cookie. Используйте текущий DateTime.UtcNow.ToString()
как значение, зашифруйте его и напишите его с помощью HttpOnly = false
.
Фильтр WebAPI выполняет следующее:
-
Ищет конкретный файл cookie в запросе. Если файл cookie существует, расшифруйте его значение и попробуйте проанализировать его как DateTime
.
-
Если значение является действительным DateTime
и составляет менее 2 дней, остановитесь здесь и ничего не делайте.
-
В противном случае бросьте исключение Forbidden 403.
Несколько заметок о моей текущей реализации этого. Прежде всего, я использую шифрование AES с общим секретом и солью. Общий секрет хранится как appSetting
в web.config. Для соли я включил анонимную идентификацию и использовал Request.AnonymousID
в качестве соли. Я не совсем люблю соль, потому что это сложно сделать в контроллере WebAPI, но не невозможно, если это не самообслуживание.