서비스 포털에 대한 전자 서명 사용

  • 릴리스 버전: Australia
  • 업데이트 날짜 2026년 03월 12일
  • 소요 시간: 15분
  • 승인 사용자의 재인증을 요구하도록 전자 서비스 포털 서명을 구성할 수 있습니다.

    시작하기 전에

    com.snc.integration.esig.window 시스템 속성은 새 창에서 SSO 로그인을 사용하도록 지원됩니다.

    필요한 역할: 관리자

    프로시저

    1. 전자 서명으로 승인 [com.glide.e_signature_approvals] 플러그인을 활성화합니다.
    2. 다음으로 이동 시스템 정의 > 전자 서명 레지스트리.
    3. 전자 서명이 필요한 테이블을 목록에 추가합니다.

    결과

    전자 서명을 활성화하면 승인자는 요청을 승인하거나 거부하기 위해 암호를 제공해야 합니다. Touch ID를 사용한 인증은 모바일 앱에서 작동합니다. 모바일 웹에서도 승인자는 암호를 입력해야 합니다. 전자 서명 구성에 대한 자세한 내용은 다음 문서를 참조하십시오 Approval with e-signature.

    새 창에서 SSO 로그인 활성화

    승인에 전자 서명을 사용하는 경우 SSO 인증을 위한 새 창을 엽니다.

    시작하기 전에

    SAML(보안 어설션 마크업 언어) 로그인은 데스크톱 서비스 포털에서만 지원됩니다.

    자세한 내용은 전자 서명 SSO 로그인 KB 문서를 참조하십시오.

    필요한 역할: 관리자

    프로시저

    1. spEsignatureCustom 스크립트를 입력합니다.
      1. 필터 탐색기에 sys_ui_script.list 를 입력합니다.
      2. 새로 만들기를 선택하고 새 UI 스크립트를 만듭니다.
      3. UI 스크립트 양식에서 API 이름 필드에 spEsignatureCustom 을 입력합니다.
      4. UI 유형 필드에서 모바일/서비스 포털을 선택합니다.
      5. 스크립트 필드에 spEsignatureCustom 스크립트를 붙여넣습니다.
      6. 제출을 선택합니다.
    2. spAuthCustom 스크립트를 입력합니다.
      1. 동일한 sys_ui_script.list 테이블에서 새로 만들기를 선택하여 다른 새 UI 스크립트를 만듭니다.
      2. UI 스크립트 양식에서 API 이름 필드에 spAuthCustom 을 입력합니다.
      3. UI 유형 필드에서 모바일/서비스 포털을 선택합니다.
      4. 스크립트 필드에 spAuthCustom 스크립트를 붙여넣습니다.
      5. 제출을 선택합니다.
    3. UI 스크립트를 JS 포함 기록에 연결합니다.
      1. 다음으로 이동 서비스 포털 > 포털.
      2. 전자 서명 지원을 적용할 서비스 포털을 식별하고 테마를 선택합니다.
      3. 관련 목록에서 JS 포함을 선택합니다.
      4. 새로 만들기를 선택합니다.
      5. 양식에서 필드를 채웁니다.
        표 1. JS 포함 양식
        필드 설명
        표시 이름 JS 포함의 이름입니다. spEsignatureCustom을 입력하고 생성한 spEsignatureCustom UI 스크립트에 레코드를 연결하거나 spAuthCustom을 입력하고 생성한 spAuthCustom에 레코드를 연결합니다.
        소스 JS 포함 기록의 소스입니다. UI 스크립트를 선택합니다.
        UI 스크립트 JS 포함 기록의 UI 스크립트 소스입니다. 생성하는 기록에 따라 spEsignatureCustom 또는 spAuthCustom을 선택합니다.
        애플리케이션 JS 포함 기록에 대한 애플리케이션입니다. 기본 애플리케이션은 전역입니다.
        업데이트됨 기록이 마지막으로 업데이트된 시기를 표시하는 필드입니다.
        패키지 JS 포함 패키지를 설정하는 필드입니다.
      6. 제출을 선택합니다.

    결과

    승인에 전자 서명을 사용하면 새 창이 열립니다.

    spEsignatureCustom 스크립트

    spEsignatureCustom 스크립트를 sys_ui_script.list 스크립트 필드에 붙여넣습니다.

    angular.module('sn.$sp').provider('spEsignature', function() {
    	'use strict';
    
    	this.$get = function spEsignature($q, $http, $window, urlTools, xmlUtil) {
    		var w = window;
    		var esignOW;
    		var windowWidth;
    		var windowHeight;
    		var redirectURL;
    
    		function isWindowChosen() {
    			var postParams = {
    				sysparm_scope: 'global',
    				sysparm_processor: 'ESignatureAuthUtils',
    				sysparm_name: 'isWindowChosen'
    			};
    			return $http({
    				method: 'POST',
    				url: '/xmlhttp.do',
    				data: urlTools.encodeURIParameters(postParams),
    				headers: {
    					'Content-Type': 'application/x-www-form-urlencoded'
    				},
    				transformResponse: function(response) {
    					return xmlUtil.getDataFromXml(response);
    				}
    			}).then(
    				function(response) {
    					var data = response.data ? response.data[0] : {};
    					return data.answer ===  'true'
    				},
    				function(response) {
    					// Handling failure case.
    					switch (response.status) {
    						default:
    						case 404:
    							return false;
    					}
    				});
    		}
    
    		function initiateEsignature() {
    			var postParams = {
    				sysparm_scope: 'global',
    				sysparm_processor: 'ESignatureAuthUtils',
    				sysparm_name: 'fetchAuthDetails'
    			}
    			return $http({
    				method: 'POST',
    				url: '/xmlhttp.do',
    				data: urlTools.encodeURIParameters(postParams),
    				headers: {
    					'Content-Type': 'application/x-www-form-urlencoded'
    				},
    				transformResponse: function(response) {
    					return xmlUtil.getDataFromXml(response, 'result');
    				}
    			}).then(
    				function(response) {
    					var data = response.data ? response.data[0] : {};
    					process(data);
    				});
    		}
    
    		function process(data) {
    			var shouldLogoutFirst = data.logoutFirst === 'true';
    			w['windowHeight'] = data.popup_window_height;
    			w['windowWidth'] = data.popup_window_width;
    			w['redirectURL'] = data.loginURL;
    			if (shouldLogoutFirst)
    				openEsignatureWindow(data.logoutURL);
    			else
    				authenticate();
    		}
    
    		function openEsignatureWindow(url) {
    			w['esignOW'] = window.open(url, 'esignatureAuthentication',
    				'height='+w['windowHeight']+',width='+w['windowWidth']+',top=100,left=100,toolbar=0,location=0,menubar=0');
    		}
    
    		w['authenticate'] = function(){
    			if(w['redirectURL']){
    				if(w['esignOW']) //when we signed out previously, a window is already opened. reuse it.
    					w['esignOW'].location.href = w['redirectURL'];
    				else
    					openEsignatureWindow(w['redirectURL']);
    			}
    		};
    
    		w['evaluateRedirect'] = function(msg) {
    			w['esignOW'].close();
    			if (msg == "saml2 login complete") {
    				$window.onReauthenticationComplete(msg);
    			}
    		};
    
    		return {
    			isWindowChosen: isWindowChosen,
    			initiateEsignature: initiateEsignature
    		};
    
    	};
    });
    

    spAuthCustom 스크립트

    spAuthCustom 스크립트를 sys_ui_script.list 스크립트 필드에 붙여넣습니다.

    angular.module('sn.$sp').factory('spAuthModal', function($q, spModal, i18n, $http, spAuthentication, glideUserSession, cabrillo, $cookies, $window, spUtil, $uibModal, spEsignature) {
    	"use strict";
    
    	function _showAuthenticationModal(requestParams, username, userSysId) {
    		var currentUser;
    		var deferred = $q.defer();
    		glideUserSession.loadCurrentUser({reload: true}).then(function(user) {
    			if (!user) {
    				deferred.reject({
    					error: {
    						status: 'ANONYMOUS',
    						message: i18n.getMessage('Not logged in')
    					}
    				});
    				return;
    			}
    			currentUser = user;
    			var serializedUser = {
    				sysId: currentUser.userID,
    				userName: currentUser.userName,
    				firstName: currentUser.firstName,
    				lastName: currentUser.lastName
    			};
    
    			// hand off to native clients
    			if (cabrillo.isNative()) {
    				cabrillo.auth.reauthenticate(currentUser).then(function() {
    					deferred.resolve(serializedUser);
    				}, function(error) {
    					if (error && error.status) {
    						deferred.reject({
    							error: error
    						});
    					}
    					//TODO: Handle rejection a little more gracefully
    					deferred.reject();
    				});
    				return;
    			}
    
    			var loginMethod = currentUser.$private.loginMethod;
    			if (!loginMethod) {
    				// As we were unable to determine the login method via the HTTP session, trying to get glide_sso_id cookie which is set in case of multisso login
    				var providerSysId = $cookies.get('glide_sso_id');
    				loginMethod = providerSysId ? 'multisso' : 'db';
    			}
    
    			if (loginMethod === 'saml' || loginMethod === 'oidc' || loginMethod === 'multisso') {
    				spEsignature.isWindowChosen().then(function(result) {
    					var modal;
    					if (!spUtil.isMobile() && loginMethod !== 'oidc' && result === true) {
    						// If enabled, Opening a new window for desktop saml login
    						spEsignature.initiateEsignature();
    					} else {
    						glideUserSession.getSsoReauthenticationUrl().then(function(url) {
    							requestParams.externalLoginURL = url;
    							openExternalAuthModal(requestParams).then(function(m) {
    								modal = m;
    							});
    						});
    					}
    					$window.onReauthenticationComplete = function(result) {
    						deferred.resolve(serializedUser);
    						if (modal)
    							modal.close();
    					};
    				});
    			} else {
    				spModal.open({
    					title:i18n.getMessage("Approver authentication"),
    					message:i18n.getMessage("Additional authentication is required, enter your usename and password to continue."),
    					footerStyle: {border: 'none', 'padding-top': 0},
    					widget: 'simpleloginui',
    					widgetInput: {},
    					shared: requestParams,
    					onSubmit: function() {
    						return onLoginModalSubmit(requestParams, username);
    					}
    				}).then(function(confirm) {
    					if (confirm.label == i18n.getMessage("OK")) {
    						deferred.resolve(serializedUser);
    					} else {
    						deferred.reject();
    					}
    				});
    			}
    		});
    
    		return deferred.promise;
    	}
    
    	function onLoginModalSubmit(requestParams, username) {
    		//(1) call login service to verify auth
    		//(2) verify same user
    		return $q(function(resolve, reject) {
    			var errorMessage = null;
    
    			if(!requestParams.username || requestParams.username.trim() === "" ||
    					!requestParams.password || requestParams.password.trim() === "") {
    				errorMessage = i18n.getMessage("User name or password invalid");
    			} else if(requestParams.username !== username) {
    				errorMessage = i18n.getMessage("Attempted to authenticate as a different user");
    			}
    
    			if(!errorMessage || errorMessage === "") {
    				spAuthentication.validateCreds(requestParams.username, requestParams.password).then(function(res) {
    					resolve({status: res.success, errorMessage: res.message});
    				});
    			} else {
    				resolve({status: !errorMessage || errorMessage === "", errorMessage: errorMessage});
    			}
    		});
    
    	}
    
    	function openExternalAuthModal(requestParams) {
    		var deferred = $q.defer();
    
    		var options = {
    			title: i18n.getMessage("Approver authentication"),
    			message: '',
    			messageOnly: false,
    			errorMessage: '',
    			input: false,
    			label: '',
    			size: 'lg',
    			value: '',
    			required: false,
    			footerStyle: {border: 'none', 'padding-top': 0},
    			values: false,
    			onSubmit: null,
    			widget: 'simpleloginui',
    			widgetInput: {},
    			shared: requestParams,
    			buttons: [{label: i18n.getMessage('Cancel'), cancel:true}]
    		};
    
    		var widgetURL = spUtil.getWidgetURL(options.widget);
    		$http.post(widgetURL, options.widgetInput).success(function(response) {
    			options.widget = response.result;
    			options.widget.options.shared = options.shared;
    			var modal = $uibModal.open({
    				templateUrl:'sp-modal.html',
    				controller: spModalCtrl,
    				size: options.size,
    				resolve: {
    					options: function() {
    						return options;
    					}
    				}
    			});
    
    			deferred.resolve(modal);
    		});
    		
    		return deferred.promise;
    	}
    
    	function spModalCtrl($scope, options) {
    		$scope.options = options;
    		$scope.form = {};
    
    		$scope.buttonClicked = function(button){
    			if (button.cancel) {
    				$scope.$dismiss();
    				return;
    			}
    		}
    	}
    
    	return {
    		prompt: _showAuthenticationModal
    	}
    }).decorator("spAuthModal", function($delegate) { return( $delegate );});