Я чувствую, что в этом посте три вопроса:
- Как программно создавать пользователей и группы?
- Как работает система прав доступа?
- Есть ли пример для текста, цитируемого со страницы прав доступа
Первый ответ на второй.
Как работает система прав доступа - на примере
В XWiki есть фиксированное количество прав, например view
, edit
и др. c.
Пользователи могут получить эти права, назначенные непосредственно им, или они могут быть членами группы, и группа имеет эти права, назначенные им. Это назначение прав может происходить в разных местах (которые в документации называются «уровнями»).
Структура «уровней» выглядит следующим образом:
Уровни вики
Во-первых, это основная вики (которая устанавливается предварительно при установке вики). Тогда может быть больше вики, называемых «под-вики», которые вы можете создать вручную (через раздел «Вики» из меню «Бургер» в правом верхнем углу каждой вики-страницы). Это простая двухуровневая иерархия:
main wiki (always exists)
|
|--- subwiki1
|
|--- subwiki2
|
|--- subwiki3
Subwikis не может быть вложенным. Я не буду вдаваться в подробности, почему вы можете их хотеть; Часто они могут go без них. Пользователи и группы могут существовать в основной вики (что означает, что их страницы профиля находятся в основной вики), или они могут существовать в подвики (т.е. их страницы профиля есть.) Пользователи и группы из основной вики видны во всех подвики. (и может получить права, назначенные им), но не наоборот - пользователь, расположенный в подвики, не может получить специальные права в основной вики (а также не в другой подвики). Если такие пользователи получают доступ к основной вики, они рассматриваются как анонимные пользователи. Они могут только войти в подвики.
Уровни страниц
Во-вторых, (почти) все данные в вики хранятся на страницах. Эти страницы также являются вложенными, и, начиная с XWiki 7.x, они могут быть вложены сколь угодно глубоко. Это другая часть структуры «уровней».
Для каждой вики существует набор страниц «верхнего уровня», как предустановленных, так и созданных пользователем. Затем есть страницы, которые являются дочерними по отношению к этим страницам «верхнего уровня», которые, в свою очередь, могут иметь детей, и так далее. Как дополнительное осложнение, не все страницы могут иметь подстраницы. По историческому соглашению эти страницы с полным именем, оканчивающимся на WebHome
, могут иметь дочерние страницы, другие не могут. Это, вероятно, прозрачно для пользователя, но важно для программиста.
Нет единой страницы "root" для запуска иерархии. Например, для одной вики структура может выглядеть следующим образом:
Top level Third Level
Second Level Fourth Level
Main.WebHome (preinstalled "Start" page)
|
|------ Main.Search (preinstalled search page, no subpages)
|
|------ Main.SomePage.WebHome (user created page, can have children)
Sandbox.WebHome (preinstalled playground page)
|
|------ Sandbox.TestPage1 (preinstalled demo page, no subpages)
|
|------ Sandbox.TestPage2 (preinstalled demo page, no subpages)
|
|------ Sandbox.TestPage3 (preinstalled demo page, no subpages)
|
|------ Sandbox.SomePage.WebHome (user created 2nd level page, can have children)
Documentation.WebHome (user created top level page)
|
|------ Documentation.Topic1.WebHome (user created 2nd level page, can have children)
| |
| |------ Documentation.Topic1.SubTopic1.WebHome (user created 3rd lvl page, can have children, too)
| |
| |------ Documentation.Topic1.SubTopic2.WebHome (user created 3rd lvl page, can have children, too)
| |
| |------ Documentation.Topic1.SubTopic3.WebHome (user created 3rd lvl page, can have children, too)
| | |
| | |------ Documentation.Topic1.SubTopic3.EvenMore.WebHome (user created 4th lvl page, can have children)
| |
| .
| .
| |
| |------ Documentation.Topic1.SubTopicN.WebHome (user created 3rd lvl page, can have children, too)
|
|------ Documentation.Topic2.WebHome (user created 2nd lvl page, can have children)
.
.
.
|
|------ Documentation.TopicN.WebHome (user created 2nd lvl page, can have children)
....
Предоставление прав
Теперь вы можете предоставить право пользователю или группе на каждой странице в этой иерархии, добавив объект типа XWiki.XWikiRights
для самой страницы, с указанием списка прав для предоставления (запутанно хранящегося в атрибуте levels
этого объекта), списка пользователей и / или групп, которым предоставляется право, и allow/deny
флаг ... к которому мы придем позже. Как это сделать программно, обсуждается в вопросе: Установить права пользователя и группы на документ в XWiki
В этом случае право предоставляется только для страницы сама , не ее подстраницы. Если вы предоставите право edit
на странице Main.WebHome
группе XWiki.HomepageEditorsGroup
, то редактировать страницу могут только члены этой группы, но это не влияет на подстраницы, такие как Main.Search
или Main.SomePage.WebHome
.
.
То, что атрибут levels
здесь фактически хранит права, может сбивать с толку - опять же, это еще одно историческое решение. (Программное обеспечение разрабатывается примерно 15 лет назад, и разработчики обязаны поддерживать обратную совместимость). Что бы ни называли атрибутом, это права , а не уровней , о которых говорится в документации.
К go в управлении правами: Вы можете также предоставьте право на страницу и все ее подстраниц . Это работает только для страниц, которые могут иметь подстраницы. Технически это достигается добавлением объекта типа XWiki.XWikiGlobalRights
... но не на саму страницу, а на подстраницу с именем WebPreferences
. (Историческое решение, опять же.)
Итак, если вы хотите предоставить view
право группе XWiki.Topic1ViewerGroup
на странице Documentation.Topic1.WebHome
и ее подстраницах, таких как Documentation.Topic1.SubTopic1.WebHome
или Documentation.Topic1.SubTopic3.EvenMore.WebHome
, то вы возьмите страницу Documentation.Topic1.WebPreferences
(создайте ее, если она не существует) и добавьте к ней объект типа XWiki.XWikiGlobalRights
с атрибутами:
level : view
groups : XWiki.Topic1ViewerGroup
allow: 1
Как проверяются права
Теперь проверка определенного права c обычно просматривает саму данную страницу, затем просматривает WebPreferences
этой страницы, затем WebPreferences
родительской страницы и так далее. (Он «поднимается по уровням».) Проверка прекращается, как только обнаруживается «объект» прав, охватывающий рассматриваемое право.
Если не найден соответствующий объект «прав» до самого верха Уровень страницы, то вики проверяется. Права на уровне вики хранятся на специальной странице XWiki.XWikiPreferences
, опять же, как объекты класса XWiki.XWikiGlobalRights
.
Наконец, если вики оказывается подвики, можно обратиться к глобальным правам в основной вики. - снова на именах страниц XWiki.XWikiPreferences
, но на этот раз в основной вики.
Пример 1: проверка на view
прямо на Documentation.Topic1.SubTopic3.WebHome
Documentation.Topic1.SubTopic3.WebHome
имеет нет XWiki.XWikiRights
- нет решения Documentation.Topic1.SubTopic3.WebPreferences
не имеет XWiki.XWikiGlobalRights
- нет решения Documentation.Topic1.WebPreferences
имеет XWiki.XWikiGlobalRights
для view
- прекратить принимать решение - Результат: если текущий пользователь находится в группе
XWiki.Topic1ViewerGroup
, он / она может просматривать страницу, в противном случае он не
Пример 2: проверка на edit
прямо на Main.WebHome
Main.WebHome
имеет XWiki.XWikiRights
для edit
- прекратить принимать решение - Результат: редактировать могут только пользователи в
XWiki.HomepageEditorsGroup
, другие не
Пример 3: проверка на edit
прямо на Main.SomePage.WebHome
Main.SomePage.WebHome
не имеет XWiki.XWikiRights
- нет решения Main.SomePage.WebPreferences
имеет нет XWiki.XWikiGlobalRights
- нет решения - вверх по странице иерархия:
Main.WebPreferences
не имеет XWiki.XWikiGlobalRights
- также не принято решение - (что
Main.WebHome
имеет XWiki.XWikiRights
, не учитывается, поскольку это право распространяется только на саму страницу) - вверх по иерархии страниц: мы уже на странице верхнего уровня, поэтому go для вики вместо
- т.е. проверяем
XWiki.XWikiPreferences
для XWiki.XWikiGlobalRights
для edit
- обычно
allow : 1
для XWiki.XWikiAllGroup
означает, что edit
разрешено для всех пользователей - , если таких настроек нет, и мы находимся в подвики: go вверх по иерархии вики и проверьте
XWiki.XWikiPreferences
из main wiki - , если даже решение не принято, право
edit
не разрешено
admin
является особым случаем
Как упрощение для пользователей, но усложнение концепции, право admin
работает наоборот: если право admin
предоставляется на уровне вики , это действительно на всех страницах. Более того, он косвенно предоставляет все остальные права, такие как view
и edit
. (Причина этого в том, что пользователи слишком часто блокировали себя до того, как было введено это специальное правило.)
Как работает «неявное запрещение»?
Теперь к цитате:
- Когда право разрешено на данном уровне, оно неявно отказывается кому-либо еще на том же уровне . Это относится только к разрешенному праву. Если на этом уровне для пользователя / группы установлен только «Вид», все остальные права, такие как «Редактировать», по-прежнему наследуются. Использование этого неявного поведения запрета рекомендуется вместо применения явного отказа.
Я также пытаюсь объяснить примером:
В Примере 1 выше Я написал:
Documentation.Topic1.WebPreferences
имеет XWiki.XWikiGlobalRights
для view
- прекратить принимать решение - Результат: если текущий пользователь находится в группе
XWiki.Topic1ViewerGroup
, он / она может просматривать страницу, в противном случае не
Здесь результат либо:
- позволяет пользователю просматривать страницу (и ее подстраницы), если пользователь является членом
XWiki.Topic1ViewerGroup
- лишает пользователя права на просмотр страницы (и ее подстраниц), если пользователь не является членом
XWiki.Topic1ViewerGroup
(то есть является "всеми остальными")
То есть независимо от того, какие права пользователь может иметь в противном случае - как только это право будет установлено здесь, только пользователям, отвечающим критерию в настройках, будет разрешено просматривать. Все остальные отсутствуют. Это " неявное запрещение ".
В качестве альтернативы предположим, что кто-то установил объект прав на Sandbox.WebPreferences
(то есть влияет на "Песочницу" и все подстраницы):
level : edit
groups : XWiki.Topic1ViewerGroup
allow: 1
и Sandbox.SomePage.WebHome
(т.е. влияет только на эту подстраницу):
level : edit
groups : XWiki.Topic1ViewerGroup
allow: 0
Настройка allow: 0
- это " явный отказ": как только вы станете участником XWiki.Topic1ViewerGroup
, вы не сможете редактировать эту страницу. Тот факт, что существует allow: 1
на более высоком уровне в иерархии страниц (в «Песочнице» и на всех вложенных страницах), не имеет значения, поскольку он не на том же уровне .
Как это сделать программно?
Во-первых, группы должны быть созданы как «терминальные» подстраницы (т. Е. Страницы, не имеющие дочерних элементов) в пространстве XWiki
, например XWiki.MyCustomGroup
. Однако кажется, что они работают везде, где вы хотите их создать.
С другой стороны, пользователи должны быть созданы в виде страниц XWiki.<LoginName>
, к сожалению, существует много кода, который ожидает пользователей находиться в этом месте и нигде больше.
После создания страницы (в API они называются Document
), добавьте объект соответствующего класса на страницу, установите нужные атрибуты и сохраните страницы.
При рассмотрении ваших требований не похоже, что вы хотите предоставить права группам в каком-либо особом месте в иерархии страниц; поэтому я предполагаю, что они будут установлены на уровне вики. Таким образом, нет необходимости понимать все другие объяснения; просто возьмите страницу XWiki.XWikiPreferences
и добавьте туда XWiki.XWikiGlobalRights
.
Я рекомендую использовать для этого MandatoryDocumentInitializer ; в базе кода есть хороший пример , который гарантирует, что XWikiAllGroup
всегда присутствует. Этот интерфейс предназначен для того, чтобы гарантировать, что в вики присутствует одна страница, но никто не мешает вам также проверить, правильно ли настроены другие страницы. Единственное, что вам нужно иметь в виду, это то, что другие страницы не сохраняются автоматически, но вы можете сделать это вручную с помощью метода XWiki.saveDocument
.
Для создания пользователя в классе XWiki
существует удобный метод XWiki.createUser(String userName, Map values, XWikiContext context)
. Карта values
содержит значения атрибутов, которые будут установлены для нового пользователя; Вы можете проверить, какие атрибуты доступны на странице XWiki.XWikiUsers
в вашей вики.
Чтобы создать группу, вы можете позаимствовать код из приведенного выше примера. Обратите внимание, что для создания новой пустой группы добавляется объект типа XWiki.XWikiGroups
; Чтобы добавить участников в группу, необходимо добавить еще один объект типа XWiki.XWikiGroups
для каждого пользователя и установить для атрибута member
полное имя пользователя (т. е. включая префикс 'XWiki`).
Таким образом, класс может начинаться с:
@Component
@Named("XWiki.MyStandardGroup")
public class MyUserAndGroupsInitializer implements MandatoryDocumentInitializer
{
private static final String GROUP_CLASS_NAME = "XWikiGroups";
private static final String MEMBER_ATTR = "member";
private static final String RIGHTS_CLASS_NAME = "XWikiGlobalRights";
private static final String GROUPS_ATTR = "groups";
private static final String USERS_ATTR = "users";
private static final String RIGHTS_ATTR = "levels"; // ;)
private static final String ALLOW_ATTR = "allow";
@Inject
Provider<XWikiContext> contextProvider;
@Inject
org.slf4j.Logger logger;
* @Named
содержит условно название страницы, о которой заботится инициализатор. Это позволяет избежать столкновения имен между инициализаторами, с одной стороны, и позволяет перезаписать существующий инициализатор для страницы, если это необходимо. Здесь вы можете выбрать другое имя, если хотите.
* * * * * * * * * * * * Компоненты @Inject
являются средством доступа к текущему «контексту», что позволяет нам получать доступ к данным в текущей вики и отображать соединение с базой данных в фон. Регистратор также не может повредить.
Поскольку нам нужно реализовать MandatoryDocumentInitializer
, нам сначала нужно указать местоположение одной из страниц, которые нас интересуют:
@Override
public EntityReference getDocumentReference()
{
return new LocalDocumentReference(XWiki.SYSTEM_SPACE, "MyStandardGroup");
}
Это делает XWiki передать нам на странице в качестве параметра в следующем методе; мы должны вернуть true
здесь, если эту страницу нужно сохранить позже. Поскольку мы делаем все сами, мы всегда можем вернуть false
.
@Override
public boolean updateDocument(XWikiDocument document)
{
logger.info("try to create users/groups");
try {
// here create your users
// and your groups
} catch (XWikiException xe) {
// as we are not allowed to let this through:
logger.error("failed to create groups", xe);
}
return false;
}
Вот и все, в основном. О, некоторые, возможно, полезные помощники:
Добавление пользователей относительно просто:
private void createUser(String userFullName) throws XWikiException
{
XWikiContext context = contextProvider.get();
XWiki xwiki = context.getWiki();
Map<String,String> values = new HashMap<>();
values.put("last_name", userFullName);
values.put("password", "staple battery horses correct");
int result = xwiki.createUser(userName, values, context);
if (result > 0) {
logger.info("user [{}] created", userFullName);
} else {
logger.debug("user [{}] aleady exists", userFullName);
}
}
хорошо, возможно, не , что просто, но вы можете начать с этого.
Это почти то же самое для групп:
// pass in rights as comma separated string, e.g.: "view,comment,edit"
// members should be the full page name of the user, including the "XWiki." part
private void createGroup(String group, String rights, String... members) throws XWikiException
{
logger.info("try to create group [{}]", group);
XWikiDocument groupDoc = checkDocument(XWiki.SYSTEM_SPACE + '.' + group);
if (groupDoc.isNew()) {
addUserToGroup(groupDoc, "");
for (String member : members) {
addUserToGroup(groupDoc, member);
}
XWikiContext context = contextProvider.get();
XWiki xwiki = context.getWiki();
xwiki.saveDocument(groupDoc, "created", false, context);
logger.info("group [{}] created", group);
}
setRightsForGroup(groupDoc, rights);
}
и добавить пользователей в группу также легко:
// return true if group needs to be saved afterwards
private boolean addUserToGroup(XWikiDocument groupDoc, String userName) throws XWikiException
{
XWikiContext context = contextProvider.get();
LocalDocumentReference groupClassReference = new LocalDocumentReference(XWiki.SYSTEM_SPACE, GROUP_CLASS_NAME);
// first check if the user is already member of the group
if (groupDoc.getXObject(groupClassReference, MEMBER_ATTR, userName, false) != null) {
// is already member, no changes necessary
logger.debug("user [{}] is already member of group [{}]", userName, groupDoc.getFullName());
return false;
}
logger.info("add user [{}] to group [{}]", userName, groupDoc.getFullName());
BaseObject newGroupEntry = groupDoc.newXObject(groupClassReference, context);
newGroupEntry.setStringValue(MEMBER_ATTR, userName);
return true;
}
... если бы не было настройки прав, которые я перенес в отдельный помощник
// set rights settings for group if it is not set yet; saves the result right away
private void setRightsForGroup(XWikiDocument groupDoc, String rights) throws XWikiException
{
XWikiContext context = contextProvider.get();
XWiki xwiki = context.getWiki();
LocalDocumentReference rightsClassReference = new LocalDocumentReference(XWiki.SYSTEM_SPACE, RIGHTS_CLASS_NAME);
String groupName = groupDoc.getFullName();
// check if the right is already set in the XWikiPreferences.
// here we need to loop over all values instead
XWikiDocument xwikiPrefDocument = xwiki.getDocument(new DocumentReference(context.getWikiId(), XWiki.SYSTEM_SPACE, "XWikiPreferences"), context);
boolean found = false;
for (BaseObject rightsSetting : xwikiPrefDocument.getXObjects(rightsClassReference)) {
if (rights.contentEquals(rightsSetting.getStringValue(RIGHTS_ATTR))
&& rightsSetting.getIntValue(ALLOW_ATTR) == 1) {
// this is the right setting!
String groups = rightsSetting.getStringValue(GROUPS_ATTR);
if (!groups.contains(groupName)) {
// our group is missing: add group and save
rightsSetting.setStringValue(GROUPS_ATTR, groups + ',' + groupName);
xwiki.saveDocument(xwikiPrefDocument, "add rights for group [" + groupName + "]", true, context);
logger.info("amended rights for group [{}]", groupName);
} else {
logger.info("rights for group [{}] already set", groupName);
}
found = true;
break;
}
}
if (!found) {
BaseObject newRightsSetting = xwikiPrefDocument.newXObject(rightsClassReference, context);
newRightsSetting.setStringValue(RIGHTS_ATTR, rights);
newRightsSetting.setIntValue(ALLOW_ATTR, 1);
newRightsSetting.setLargeStringValue(GROUPS_ATTR, groupName);
if (newRightsSetting.getIntValue(ALLOW_ATTR) != 1) {
logger.error("adding rights of class [{}] for group [{}] failed!", rightsClassReference, context);
}
xwiki.saveDocument(xwikiPrefDocument, "add rights for group [" + groupName + "]", true, context);
logger.info("added new rights for group [{}]", groupName);
}
}
Я также использовал помощник checkDocument
, который в основном совпадает с updateDocument
в XWikiAllGroupInitializer , за исключением что имя вводится, а утомительно новая настроенная страница является возвращаемым значением.
Возможно, вы захотите прочитать Руководство по компонентам , чтобы понять, как вводятся необходимые зависимости. Особенно вам нужно будет добавить полное имя класса инициализатора в src/main/resources/META-INF/components.txt
, чтобы инициализатор активировался.
Сделайте резервную копию базы данных, прежде чем попробовать это. За исключением нескольких попыток, прежде чем все будет правильно настроено, и при каждом перезапуске вики ничего не будет сохранено без необходимости. Также возьмите WEB-INF/classes/logback.xml
для установки уровня INFO
для вашего пакета, если вы хотите видеть сообщения журнала.
Несколько других случайных советов
Вместо управления своим пользователям программно вы можете подумать о том, чтобы затем сохранить его на сервере LDAP и использовать его для аутентификации с помощью LDAP Authenticator . (Тем не менее, вам все еще нужно создавать группы и управлять их правами)
При разработке я обнаружил, что очень полезно иметь расширение Справочная документация по сценариям , установленное в моей вики-разработке. Он не является заменой какой-либо документации, но возможность интерактивного использования API Javado c мне как-то очень помогает.
Расширение Admin Tools имеет страницу, которая показывает вам все Права предоставляются в текущей вики, где установлено это расширение. (Go до .../xwiki/bin/view/Admin/
и нажмите «Показать права».)