Защита действия контроллера ASP.NET MVC, который возвращает JSON - PullRequest
8 голосов
/ 02 мая 2011

У меня есть приложение MVC3, и действия моего контроллера защищены с помощью атрибута [Authorize]. Пока все хорошо, формы auth работают отлично. Теперь я хочу добавить JSON API в свое приложение, чтобы некоторые действия были доступны для клиентов, не являющихся браузерами.

У меня проблемы с определением правильного дизайна.

1) У каждого пользователя есть секретный ключ API.

2) Идентификатор пользователя 5 вызывает http://myapp.com/foocontroller/baraction/5?param1=value1&param2=value2&secure_hash=someValue. Здесь secure_hash - это просто SHA1-хэш param1 и значений param2, к которому добавлен секретный ключ API для пользователя

2) / foocontroller / baraction будет украшен [CustomAuthorize]. Это будет реализация AuthorizeAttribute, которая проверит, поступает ли запрос как JSON. Если это так, он проверит хеш и посмотрит, совпадает ли он. В противном случае, если запрос HTML, я вызываю существующую авторизацию.

Я совсем не уверен, сработает ли это. Это нормально для передачи безопасного хэша в строке запроса или я должен передавать его в качестве заголовка HTTP? Лучше использовать базовую аутентификацию HTTP вместо хеша, созданного с использованием секретного ключа API?

Приветствуются советы от любого, кто создал веб-API с использованием ASP.NET MVC!

1 Ответ

11 голосов
/ 02 мая 2011

Я передаю секретный ключ API вместе с именем пользователя и паролем в теле запроса.После авторизации генерируется токен, и клиент должен передать его в заголовке авторизации.Это проверяется в базовом контроллере при каждом запросе.

  1. Клиент вызывает myapp.com/authorize, который возвращает токен авторизации.
  2. Клиент сохраняет токен аутентификации локально.
  3. Клиент вызывает myapp.com/anycontroller, используя authtoken в заголовке авторизации.

AuthorizeController наследуется от контроллера.Anycontroller наследуется от пользовательского базового контроллера, который выполняет код авторизации.

В моем примере требуется следующий маршрут, который направляет запросы POST в именованное сообщение ActionResult на любом контроллере.Я набираю это вручную, чтобы максимально упростить, чтобы дать вам общее представление.Не ожидайте вырезать и вставлять и заставить его работать:)

routes.MapRoute(
    "post-object",
    "{controller}",
    new { controller = "Home", action = "post" {,
    new { httpMethod = new HttpMethodConstraint("POST")}
);

Ваш контроллер аутентификации может использовать это

public class AuthorizationController : Controller
{
    public ActionResult Post()
    {
        string authBody;
        var request = ControllerContext.HttpContext.Request;
        var response = ControllerContext.HttpContext.Response;

        using(var reader = new StreamReader(request.InputStream))
            authBody = reader.ReadToEnd();

        // authorize based on credentials passed in request body
        var authToken = {result of your auth method}

        response.Write(authToken);

    }
}

Другие ваши контроллеры наследуются от базового контроллера

public class BaseController : Controller
{
    protected override void Execute(RequestContext requestContext)
    {
        var request = requestContext.HttpContext.Request;
        var response = requestContext.HttpContext.Response;

        var authToken = Request.Headers["Authorization"];

        // use token to authorize in your own method
        var authorized = AmIAuthorized();

        if(authorized = false) { 
            response.StatusCode = 401; 
            response.Write("Invalid token");
            return;            
        }

        response.StatusCode = 200; // OK

        base.Execute(requestContext);  // allow inheriting controller to continue

    }
}

Пример кода для вызова API

 public static void ExecutePostRequest(string contentType)
        {
            request = (HttpWebRequest)WebRequest.Create(Uri + Querystring);
            request.Method = "POST";
            request.ContentType = contentType;  // application/json usually
            request.Headers["Authorization"] = token;

            using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
                writer.Write(postRequestData);

            // GetResponse reaises an exception on http status code 400
            // We can pull response out of the exception and continue on our way            
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;
            }
            finally
            {
                using (StreamReader reader =
                    new StreamReader(response.GetResponseStream()))
                    responseText = reader.ReadToEnd();
                httpcontext = HttpContext.Current;
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...