Вызов механизма OAuth для DevOps Azure через ajax или с помощью других средств, таких как атрибут [Authorize] - PullRequest
1 голос
/ 01 апреля 2019

Я пытаюсь создать рабочий элемент в DevOps Azure программно, используя OAuth в качестве механизма аутентификации.У пользователей будет форма ввода, в которой будут вводиться тексты, выпадающие списки и т. Д. Для написания описания, выбора Назначено и т. Д. Я получу и использую его для связывания соответствующих полей в DevOps Azure и создания рабочего элемента на имя пользователя.Я передал этот код https://github.com/Microsoft/azure-devops-auth-samples/tree/master/OAuthWebSample/OAuthWebSample/ для реализации OAuth.

Теперь этот код, предоставленный в github, отлично работает как отдельный пользователь.Однако у меня есть некоторые трудности, чтобы объединить его с моим кодом.

Сначала я пишу простой код, взятый из github, который работает нормально, а затем я напишу свой код, который я хочудля интеграции с прежним

Это простой код , где у меня просто есть кнопка в пользовательском интерфейсе (скажем, кнопка «Авторизовать»), которая при нажатии вызывает Authorize ActionResult в OAuthконтроллер.Вот код:

private static readonly Dictionary<Guid, TokenModel> s_authorizationRequests = new Dictionary<Guid, TokenModel>();
public ActionResult Authorize()
{
     Guid state = Guid.NewGuid();

     s_authorizationRequests[state] = new TokenModel() { IsPending = true };

     return new RedirectResult(GetAuthorizationUrl(state.ToString()));
}

TokenModel - это класс, используемый для десериализации Json впоследствии.Отсюда он вызывает метод GetAuthorizationUrl и создает URI.

private static String GetAuthorizationUrl(String state)
        {
            UriBuilder uriBuilder = new UriBuilder(ConfigurationManager.AppSettings["AuthUrl"]);
            var queryParams = HttpUtility.ParseQueryString(uriBuilder.Query ?? String.Empty);

            queryParams["client_id"] = ConfigurationManager.AppSettings["ClientAppId"];
            queryParams["response_type"] = "Assertion";
            queryParams["state"] = state;
            queryParams["scope"] = ConfigurationManager.AppSettings["Scope"];
            queryParams["redirect_uri"] = ConfigurationManager.AppSettings["CallbackUrl"];

            uriBuilder.Query = queryParams.ToString();

            return uriBuilder.ToString();
        }

Затем он автоматически перенаправляет на метод Callback, который является моим CallbackUrl с кодом авторизации, если пользователь принял Условия, и генерирует маркер доступа, которыйзатем просто передается в представление.

public async Task<ActionResult> Callback(String code, Guid state)
        {
            String error;
            if (ValidateCallbackValues(code, state.ToString(), out error))
            {
                // Exchange the auth code for an access token and refresh token
                HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, ConfigurationManager.AppSettings["TokenUrl"]);
                requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                Dictionary<String, String> form = new Dictionary<String, String>()
                {
                    { "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" },
                    { "client_assertion", ConfigurationManager.AppSettings["ClientAppSecret"] },
                    { "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer" },
                    { "assertion", code },
                    { "redirect_uri", ConfigurationManager.AppSettings["CallbackUrl"] }
                };
                requestMessage.Content = new FormUrlEncodedContent(form);

                HttpResponseMessage responseMessage = await s_httpClient.SendAsync(requestMessage);

                if (responseMessage.IsSuccessStatusCode)
                {
                    String body = await responseMessage.Content.ReadAsStringAsync();

                    TokenModel tokenModel = s_authorizationRequests[state];
                    JsonConvert.PopulateObject(body, tokenModel);
                    //ViewBag.DeliverableId = WorkItemsHelper.CreateWorkItem(tokenModel.AccessToken);
                    ViewBag.Token = tokenModel;
                }
                else
                {
                    error = responseMessage.ReasonPhrase;
                }
            }

            if (!String.IsNullOrEmpty(error))
            {
                ViewBag.Error = error;
            }

            ViewBag.ProfileUrl = ConfigurationManager.AppSettings["ProfileUrl"];

            return View("TokenView");
        }

Эта штука прекрасно работает до сих пор.Но теперь я хочу достичь и попробовать следующее: Теперь я хочу добиться этого с помощью формы ввода, например, (будут другие поля)

<div class="form-row">
      <div class="form-group col-md-6">
        <label> Title </label>
        <input type="text" class="form-control" id="title"/>
      </div>
      <div class="form-group col-md-6">
        <label> Description </label>
        <input type="text" class="form-control" id="description"/>
      </div>
</div>
<button type="submit" class="btn btn-primary">Save</button>

Когдапользователь нажимает кнопку «Сохранить», я хочу, чтобы генерировался токен доступа, а также использовал этот маркер доступа и поля ввода от пользователя и создавал рабочий элемент в лазурных девопах.Сначала я попробовал ajax-вызов, при котором вызывал метод Authorize при нажатии кнопки сохранения

<script type="text/javascript">
    $(document).ready(function () {
        $("#testbutton").click(function () {
            $.ajax({
                type: "post",
                url: "/Oauth/Authorize",
                success: function (response) {
                    alert(response);
                    document.getElementById("returnedmessage").innerHTML = response;
                },
                error: function () {
                    alert('an error occured');
                }
            });
        });
    });
</script>

(я хотел вернуть Json (ViewBag.TokenModel.AccessToken) из метода Callback).Метод Authorize, но после этого вместо перехода к методу Callback он возвращает ответ с некоторым html, и в консоли моего браузера появляются ошибки, в которых говорится, что 404 не найдено.

Второй подход Iпытаясь следовать нажатию на кнопку «Сохранить», я вызываю метод (скажем, Index) и пытаюсь вызвать внутри него метод Authorize,

public ActionResult Index() 
{
     var s = Authorize();
     return View();
}

Но все равно он не попадает в метод CallBack и ничегослучается.

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

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

Есть ли способчто я могу сделать пользовательский атрибут, такой как атрибут Authorize, который при использовании поверх контроллера проверяет подлинность пользователей перед доступом к каким-либо методам?Или любой другой обходной путь?

Извиняюсь за длинный вопрос или если я не был достаточно ясен.Будем рады любой помощи в мелких деталях.

...