Основная конфигурация личного кабинета состоит из нескольких блоков:
- bgbilling - конфигурация подключения к BGBillingServer,
- authentication - параметры аутентификации абонента,
- mail - параметры почтовой подсистемы (чтобы ЛК мог отправлять письма при необходимости),
- content - параметры содержимого страниц.
Конфигурация подключения к BGBillingServer
// Параметры подключения к BGBillingServer. // ЛК является пользователем биллинга, общается с ним также, как BGBillingClient bgbilling { // URL доступа к BGBilling url = 'http://127.0.0.1:8080/bgbilling/executer' // Логин user = 'customer' // Пароль password = '123456' }
Параметры идентификации HTTP-соединения
Личному кабинету в некоторых случаях требуется знать базовый URL, по которому абоненты получают доступ к нему. Личный кабинет биллинга может получить это значение из запроса, однако при использовании NGINX значение из запроса может быть не правильным. Поэтому базовый URL следует указать в конфигурации в параметре baseUrl.
Также личному кабинету требуется знать IP-адрес абонента, который пользуется им в текущий момент (например, для авторизации по IP-адресу или блокировке при переборе логинов/паролей). Поэтому при использовании NGINX требуется указать HTTP-заголовок в параметре context.hostHttpRequestHeader, из которого получать реальный IP-адрес вместо физического IP-адреса HTTP-соединения.
context { // Базовый адрес сервера (через который абоненты получают доступ к ЛК). По умолчанию используется значение из запроса //baseUrl = 'https://provider.ru/selfcare' baseUrl = 'https://my.provider.ru' // Идентификатор хоста по HTTP-заголовку, например, X-Real-IP. По умолчанию используется IP-адрес хоста hostHttpRequestHeader = 'X-Real-IP' }
Параметры аутентификации абонента
// Параметры аутентификации абонента authentication { // Кол-во ошибок аутентификации, после которого будет отображаться captcha для этого логина captchaLoginErrorCount = 5 // Кол-во ошибок аутентификации, после которого будет отображаться captcha для хоста captchaHostErrorCount = 20 // Кол-во ошибок аутентификации, после которых будут заблокированы попытки этого хоста blockHostErrorCount = 30 // Режимы аутентификации для входа в ЛК modes = [ // аутентификация по номеру договора authenticationMode { mode = 'contract' } ] }
Режимов аутентификации может быть несколько - в этом случае в окне логина можно выбрать необходимый. На данный момент поддерживаются 6 режимов аутентификации:
по номеру договора:
authenticationMode { mode = 'contract' }
по логину модуля Inet:
authenticationMode { module = 'inet' mode = 'login' // ID модуля moduleId = 1 }
по IP-адресу сессии модуля Inet (вход без пароля):
authenticationMode { module = 'inet' mode = 'ip' // ID модуля moduleId = 1 // ограниченный доступ role = 'unauthCustomer' }
по параметру договора "телефон":
authenticationMode { module = 'kernel' mode = 'phoneParam' // ID параметра parameterId = 1 // преобразование введенного номера договора username = { s -> s.replaceAll( /^8(.+)$/,'7$1' ) } }
по параметру договора "Email":
authenticationMode { module = 'kernel' mode = 'emailParam' // ID параметра parameterId = 2 // преобразование введенного номера телефона username = { s -> s.replaceAll( /^8(.+)$/,'7$1' ) } }
по текстовому параметру договора:
authenticationMode { module = 'kernel' mode = 'textParam' // ID параметра parameterId = 3 }
При аутентификации по параметру договора в качестве пароля используется пароль к личному кабинету (как и при аутентификации номеру договора). При аутентификации по номеру телефона идет поиск только по введенным цифрам, при этом можно задать преобразование введенного номера в другой вид с помощью параметра username; если параметр username не указан, то по умолчанию 8 в начале строки заменяется на 7.
Для режима аутентификации можно назначить, чтобы доступ после аутентификации через него был ограничен. Для этого указывается параметр role = 'unauthCustomer'. В этом случае, вызов isUserInRole( "customer" ) будет возвращать false. Ограниченный доступ может быть указан, например, для режима аутентификации по IP-адресу модуля Inet.
Можно разрешить аутентификацию только для определенных групп договоров, указав условие в параметре filter:
authenticationMode { module = 'inet' mode = 'ip' //ID модуля moduleId = 1 // ограниченный доступ role = 'unauthCustomer' // фильтр по группам договоров filter = { contract -> contractInGroup( contract, [1, 2, 3, 4, 20] ) } }
Или наоборот, запретить для определенных групп договоров:
filter = { contract -> !contractInGroup( contract, [1, 2, 3, 4, 20] ) }
Или разрешить по номеру договора:
filter = { contract -> contract.title.startsWith( "NK" ) }
Или использовать регулярное выражение:
filter = { contract -> contract.title.matches( "NK.*" ) }
Параметры почтовой подсистемы
// Параметры SMTP, чтобы ЛК мог отправлять письма mail { smtp { host = 'smtp.provider.ru' } from { email = 'support@provider.ru' name = 'BGBilling' } }
Параметры содержимого страниц
Разрешенные фрагменты
Данный блок конфигурации позволяет настраивать, какие фрагменты страницы или какие действия доступны абонентам или группам абонентов. Например, в коде страницы статусов договора есть фрагмент смены статуса:
<ui:fragment rendered="#{configuration.get('content.kernel.status.statusChange', true)}"> ... </ui:fragment>
Соответственно можно в конфигурации запретить всем менять статус договора из личного кабинета:
content { kernel { ... // status.xhtml status { // возможность изменения статуса договора statusChange = false } ... } ... }
Можно разрешить только тем, кто был аутентифицирован по логину/паролю (в конфигурации по умолчанию установлен этот вариант):
statusChange = { isUserInRole( "customer" ) }
Разрешить только аутентифицированным по логину/паролю физ. лицам:
statusChange = { contract -> isUserInRole( "customer" ) && contract.getPersonType() == 0 }
Или разрешить только аутентифицированным по логину/паролю определенным группам договоров:
statusChange = { contract -> isUserInRole( "customer" ) && contractInGroup( contract, [1, 2, 3, 4, 20] ) }
Название контрагента в верхней части страницы
По умолчанию в шапке страницы название или имя контрагента не отображается. За отображение названия (или имени) отвечает параметр content.kernel.customerTitle. В конфигурации можно указать, чтобы отображался комментарий договора:
content { kernel { // название контрагента, отображаемое на странице customerTitle = { contract, contractParameterMap -> contract.comment } ... }
Или же отобразить параметр договора, в зависимости от типа лица договора (физ. лицо или юр. лицо):
content { kernel { // название контрагента, отображаемое на странице customerTitle = { contract, contractParameterMap -> // ID параметров договоров названия физ. лиц (для customerTitle) def individualCustomerTitleParamIds = [33, 0, 0, 0, 0]; // ID параметров договоров названия юр. лиц (для customerTitle) def corporationCustomerParamIds = [10, 0, 0, 0, 0]; def paramIds = contract.personType == 1 ? corporationCustomerParamIds : individualCustomerTitleParamIds; String result = contractParameterMap.values().stream() .filter{ v -> paramIds.contains( v.entitySpecAttrId ) && notBlankString( v.toString() ) } .findFirst() .map{ v -> v.toString() } .orElse( null ); return result; } ... } ... }
Группировка субдоговоров в меню
Если субдоговоров у данного договора меньше 10 - они отображаются прямо в меню. В этом случае можно сортировать и группировать список субдоговоров:
content { kernel { // группировка субдоговоров (для меню) subContractGroup = { subContractList -> subContractList .stream() .sorted({ a,b -> a.title.compareTo(b.title) }) .collect( Collectors.groupingBy{ contract -> // можно группировать субдоговора по группам договоров if( contractInGroup( contract, [1, 2, 3, 4, 20] ) ) { return "contract.sub.group.01.internet"; }else if( contractInGroup( contract, [5, 6, 7, 8, 9] ) ) { return "contract.sub.group.02.phone"; } else { return "contract.sub.group.99.other"; } // если всем возвращать пустую строку - то группировки не будет return ""; }) .entrySet() .stream() .sorted({ a,b -> a.key.compareTo(b.key) }) .collect( Collectors.toList() ); } ... } ... }
В примере при группировке используются строки вида "contract.sub.group.01.internet". Число в данном случае используется для сортировки групп, а само название группы должно быть прописано в Locale_ru_RU.properties по ключу:
contract.sub.group.01.internet=Интернет contract.sub.group.02.phone=Телефония contract.sub.group.99.other=Другое