Использование JSOM (CSOM, клиентская объектная модель SharePoint) в Node.js

Вступление

Не секрет, что теоретически возможно использовать JSOM в рамках процесса Node.js. Уже довольно давно в сообществе нашли способ "патчинга" контекста JSOM под Node.js окружение.

Однако, не было простого и надежного решения в виде подключаемой библиотеки. Можно было часами бороться с тем, чтобы заставить JSOM работать. А переключение между различными сценариями авторизации были болезненными, требующими порой дней разработки.

Посвященный в тематику читать может возвразить "Как на счет CSOMNode, который уже является подключаемой библиотекой?". Скажу так, это неплохой вариант и он, отчасти даже вдохновил меня для создания библиотеки, о которой далее пойдет речь. Но у CSOMNode есть ограничения в части аутентификации, а точнее возможностью использования SAML и Add-in Only, так же маловероятно, что в CSOMNode будут вносится какие либо значительные улучшения в связи с ограниченным временем и интересом у авторов. Как минимум, вопрос о возможности добавления NTLM аутентификации находится без ответа уже почти год, такая же картина и под другим тикетам, на них нет даже ответа, что "планов на реализацию нет" или "будем рады Pull Request'ам, но у нас нет возможности исправить/реализовать", просто тишина. Отчасти это понятно, с Open Source проектами такое часто бывает, требовать от авторов что-либо против воли мы не можем.

В моем случае, мне как раз требовался неподдерживаемый способ аутентификации. На других проектах я использую node-sp-auth, эта библиотека предоставляет большое число сценариев по аутентификации и замечательную поддержку автора. Помимо этого мне требовался JSOM в Node.js в рамках допольно строчной необходимости, надо было действовать.

Первой идеей было расширить CSOMNode, интегрировать node-sp-auth и отправить соответствующий Pull Request. После более детального знакомства с кодовой базой библиотеки я понял, что мой PR скорее всего не будет принят из-за того, что он по объективным причинам будет содержать много кода и правок. Из своего же опыта могу сказать, что авторы часто ревностно относятся к принятым решениям на счет структуриры кода, стилю и прочим моментам. Слишком масштабный Pull Request, насколько он не будет замечательным, скорее всего либо на долго завистен, либо вообще будет отклонен. Мои же изменения уже представлялись такими. Помимо этого, у меня выработалось отторжение к проектам на JS, TypeScript является обязательным требования в библиотеках, в рамках которых планируется поддержка и исполнение в рабочих проектах.

Исходя из вышеперечисленного я решил написать библиотеку на TypeScript, которая бы удовлетворяла современным реалиям и требованиям индустрии, а так же расширяла возможности аутентификации и упрощала обновление возможностей JSOM появляющихся в SPO.

JSOM в Node.js

Алгоритм того, как заставить JSOM работать в Node.js в целом довольно прост:

  • Необходимо расширить глобальный контекст Node.js так, чтобы он мимикрировал под браузер (пример)
  • Загружать и исполнять JS-ки ядра JSOM в определенном порядке (пример)
  • Пропатчить некоторые переменные, чтобы избавиться от части нюансов браузерной реализации (например microsoft ajax)
  • Инкапсулирповать авторизационные заголовки в запросы (пример)

Мимикрирование под браузер, загрузка JavaScript'а JSOM и патчинг переменных и объектов является допольно тривиальной частью. В большей степени реализация из CSOMNode помогла переиспользовать часть кода, конечно же со значительным рефакторингом и переносом на TypeScript. По ссылкам выше можно посмотреть как именно это было сделано.

Внедрение авторизационных заголовков оказалось более интересной и сложной задачей.

Клиентская объектная модель SharePoint на JavaScript использует библиотеку Microsoft Ajax и XmlHttpRequest. Что тут можно сказать? Это пережитки прошлого, которые приносят только боль.

Изначально я планировал внедрение авторизационных заголовков с использованием метода add_executingWebRequest:

clientContext.add_executingWebRequest((sender, e) => {
    let headers = e.get_webRequest().get_headers();
    for (let header of Object.keys(auth)) {
        if (['Cookie', 'Authorization'].indexOf(header) !== -1) {
            headers[header] = auth[header];
        }
    }
});

Да, такой подход работал... но, только в для случаев с FedAuth cookies и Bearer authorization заголовками... для NTLM конечно же - не вариант.

В этой части пришлось помучаться и поэксперементировать и еще раз помучасться. В итоге я решил, что использовать эмуляторы XmlHttpRequest я не буду и обернать свой собственный прокси для метода executeRequestWebRequestManager'а.

Оригинальный Sys.Net._WebRequestManager.prototype.executeRequest получает запросы и транслирует через XmlHttpRequest.

В моем варианте, Sys.Net._WebRequestManager.prototype.executeRequest полностью переписан для возможности использования клиентаsp-requestsp-request отвечает за внедрение ауторизационных заголовков и дайджеста, при этом, такой подход работает для всех стратегий аутентификации, включаяя NTML, ADFS, FBA и др.

Использование на примерах

Оставим лирику и перейдем к тому, как использовать библиотеку.

Представляю вашему вниманию sp-jsom-node или же JsomNode, для краткости.

JsomNode Demo

Для начала необходимо подключить записимость:

npm install sp-jsom-node --save

После того, как sp-jsom-node установлен в проект, он может быть использован как в TypeScript, так и JavaScript реализации. Примеры ниже на TypeScript, так же предполагается, что среда настроена соответствующим образом (установлены глобальные зависимотси, такие как typescript, ts-node, tslint, пр.).

Далее, нужно создвтать файл ts, например, index.ts, и вставить код примера:

import { JsomNode } from 'sp-jsom-node';

(new JsomNode()).wizard().then((settings) => {

    // Здесь можно использовать JSOM

    const ctx = SP.ClientContext.get_current();
    const oWeb = ctx.get_web();

    ctx.load(oWeb);

    ctx.executeQueryAsync(() => {
        console.log(oWeb.get_title());
    }, (sender, args) => {
        console.log(args.get_message());
    });


}).catch(console.log);

Это минимальная требуемая конструкция, как видно, требуется совсем немного и очень просто начать использовать JSOM в Node.js.

Если запустить вышеприведенный пример без какого либо дополнительного настроенного подключения в SharePoint, выполнив в консоли ts-node ./index.ts, то инициализируется мастер подключения и ввода адреса портала, способа и параметров аутентификации.

Так же есть альтарнативный способ инициализации контекста с явным указанием авторизационных опций:

import { JsomNode, IJsomNodeSettings } from 'sp-jsom-node';

const settings: any = require('./config/private.json');

const jsomNodeOptions: IJsomNodeSettings = {
    siteUrl: settings.siteUrl,
    authOptions: { ...settings }
};

new JsomNode(jsomNodeOptions).init();

/// ... <<< Здесь можно использовать JSOM

Проект содержит интеграционные тесты, проверяющие работу библиотеки с SharePoint Online, SharePoint 2016/2013. Так же, есть примеры для быстрого старта.

Заключение

Если вам требуется JSOM в Node.js, я буду рад если sp-jsom-node сможет помочь вам в достижении нужной цели. С удовольствием причитаю о ваших сценариях использования Node.js совместно с SharePoint и отвечу на возможные вопросы.


Опубликовано: 27.08.2018
Автор: Андрей Кольтяков