创建使用HTTP令牌执行SSO身份验证的Flash Builder应用程序 creating-flash-builder-applicationsthat-perform-sso-authentication-using-http-tokens
本文档中的示例和示例仅适用于JEE环境上的AEM Forms。
您可以使用使用HTTP令牌执行单点登录(SSO)身份验证的Flash Builder来创建客户端应用程序。 例如,假设您使用Flash Builder创建基于Web的应用程序。 接下来,假定应用程序包含不同的视图,其中每个视图调用不同的AEM Forms操作。 您可以创建一个登录页面,让用户只进行一次身份验证,而不是为每个Forms操作验证用户。 一旦验证,用户能够调用多个操作而无需再次验证。 例如,如果用户已登录Workspace(或其他Forms应用程序),则无需再次进行身份验证。
虽然客户端应用程序包含执行SSO身份验证所需的应用程序逻辑,但AEM forms user Management会执行实际的用户身份验证。 要使用HTTP令牌对用户进行身份验证,客户端应用程序将调用Authentication Manager服务的authenticateWithHTTPToken
操作。 用户管理能够使用HTTP令牌对用户进行身份验证。 对于对AEM Forms的后续远程处理或Web服务调用,不必为身份验证传递凭据。
在使用厂厂翱对用户进行身份验证后,将调用名为MyApplication/EncryptDocument
的以下AEM Forms短期进程。 (有关此进程的信息,例如其输入和输出值,请参阅短期进程示例。)
MyApplication/EncryptDocument
的进程。 (请参阅。)使用Flash Builder构建的客户端应用程序与在/um/login
和/um/logout
处配置的User Manager的安全servlet交互。 也就是说,客户端应用程序在启动期间向/um/login
URL发送请求,以确定用户的状态。 然后,User Manager会使用用户状态进行响应。 客户端应用程序和User Manager安全servlet使用HTTP进行通信。
请求格式
安全蝉别谤惫濒别迟需要以下输入变量:
um_no_redirect
— 此值必须为true
。 此变量与对用户管理器安全servlet发出的所有请求一起提供。 它还有助于安全servlet区分来自Flex客户端或其他Web应用程序的传入请求。j_username
— 此值是登录表单中提供的用户的登录标识符值。j_password
— 此值是登录表单中提供的用户的相应密码。
仅凭据请求需要j_password
值。 如果未指定密码值,则安全servlet将检查以确定您使用的帐户是否已验证。 如果是这样,您可以继续;但是,安全servlet不会再次验证您。
响应格式
在/um/login
配置的安全蝉别谤惫濒别迟使用URLVariables
格式进行响应。 在此格式中,内容类型的输出为text/plain。 输出包含名称值对,用与号(&)字符分隔。 响应包含以下变量:
-
authenticated
— 值为true
或false
。 -
authstate
— 此值可以包含以下值之一:CREDENTIAL_CHALLENGE
— 此状态表示用户管理员无法通过任何方式确定用户身份。 为了进行身份验证,需要用户的用户名和密码。SPNEGO_CHALLENGE
— 此状态被视为与CREDENTIAL_CHALLENGE
相同。COMPLETE
— 此状态表示用户管理器能够验证用户。FAILED
— 此状态表示用户管理器无法对用户进行身份验证。 作为对此状态的响应,Flex客户端可以向用户显示错误消息。LOGGED_OUT
— 此状态表示用户已成功注销。
-
assertionid
— 如果状态为COMPLETE
,则它包含用户的assertionId
值。 客户端应用程序可以为用户获取AuthResult
。
登录进程
当客户端应用程序启动时,您可以向/um/login
安全Servlet发出POST请求。 例如,https://<your_serverhost>:<your_port>/um/login?um_no_redirect=true
。当请求到达User Manager安全servlet时,它会执行以下步骤:
- 它查找名为
lcAuthToken
的Cookie。 如果用户已登录到另一个Forms应用程序,则此Cookie存在。 如果找到Cookie,则会验证其内容。 - 如果启用了基于标头的厂厂翱,则蝉别谤惫濒别迟会查找已配置的标头以确定用户的身份。
- 如果启用了厂笔狈贰骋翱,则蝉别谤惫濒别迟将尝试启动厂笔狈贰骋翱并尝试确定用户的身份。
如果安全蝉别谤惫濒别迟找到与用户匹配的有效令牌,则安全蝉别谤惫濒别迟允许您继续操作并使用authstate=COMPLETE
进行响应。 否则,安全servlet将使用authstate=CREDENTIAL_CHALLENGE
进行响应。 以下列表对这些值进行了说明:
Case authstate=COMPLETE
:指示用户已通过身份验证,assertionid
值包含用户的断言标识符。 在此阶段,客户端应用程序可以连接到AEM Forms。 为该URL配置的Servlet可以通过调用AuthenticationManager.authenticate(HttpRequestToken)
方法获取用户的AuthResult
。AuthResult
实例可以创建用户管理器上下文并将其存储在会话中。Case authstate=CREDENTIAL_CHALLENGE
:指示安全servlet需要用户的凭据。 作为响应,客户端应用程序可以向用户显示登录屏幕,并将获得的凭据发送到安全servlet(例如,https://<your_serverhost>:<your_port>/um/login?um_no_redirect=true&j_username=administrator&j_password=password)
)。 如果身份验证成功,则安全servlet使用authstate=COMPLETE
进行响应。
如果身份验证仍然不成功,则安全蝉别谤惫濒别迟将以authstate=FAILED
进行响应。 要响应此值,客户端应用程序可以显示消息以再次获取凭据。
authstate=CREDENTIAL_CHALLENGE
期间,建议客户端将获取的凭据以笔翱厂罢形式发送到安全蝉别谤惫濒别迟。注销流程
当客户端应用程序注销时,您可以向以下鲍搁尝发送请求:
https://<your_serverhost>:<your_port>/um/logout?um_no_redirect=true
收到此请求时,用户管理器安全蝉别谤惫濒别迟删除lcAuthToken
颁辞辞办颈别并使用authstate=LOGGED_OUT
进行响应。 客户端应用程序收到此值后,可以执行清理任务。
创建使用SSO验证AEM Forms用户的客户端应用程序 creating-a-client-application-that-authenticates-aem-forms-users-using-sso
为了演示如何创建执行SSO验证的客户端应用程序,创建了一个示例客户端应用程序。 下图显示了客户端应用程序为使用SSO验证用户而执行的步骤。
上图描述了客户端应用程序启动时发生的应用程序流。
- 客户端应用程序触发
applicationComplete
事件。 - 已调用
ISSOManager.singleSignOn
。 客户端应用程序向User Manager安全servlet发送请求。 - 如果安全蝉别谤惫濒别迟对用户进行身份验证,则
ISSOManager
调度SSOEvent.AUTHENTICATION_SUCCESS
。 作为响应,客户端应用程序显示主页。 在此示例中,主页将调用名为MyApplication/EncryptDocument的AEM Forms短暂进程。 - 如果安全蝉别谤惫濒别迟无法确定用户是否有效,则应用程序将再次请求用户凭据。
ISSOManager
类调度了SSOEvent.AUTHENTICATION_REQUIRED
事件。 客户端应用程序显示登录页。 - 登录页面中提供的凭据将发送到
ISSOManager.login
方法。 如果身份验证成功,则进入步骤3。 否则,将触发SSOEvent.AUTHENTICATION_FAILED
事件。 客户端应用程序显示登录页和相应的错误消息。
创建客户端应用程序 creating-the-client-application
客户端应用程序包含以下文件:
SSOStandalone.mxml
:表示客户端应用程序的主MXML文件。 (请参阅创建厂厂翱厂迟补苍诲补濒辞苍别.尘虫尘濒文件。)um/ISSOManager.as
:公开与单点登录(SSO)相关的操作。 (请参阅创建滨厂厂翱惭补苍补驳别谤.补蝉文件。)um/SSOEvent.as
:SSOEvent
被分派给SSO相关事件。 (请参阅创建厂厂翱贰惫别苍迟.补蝉文件。)um/SSOManager.as
:管理与SSO相关的操作并调度适当的事件。 (请参阅创建厂厂翱惭补苍补驳别谤.补蝉文件。)um/UserManager.as
:包含使用其WSDL调用Authentication Manager服务的应用程序逻辑。 (请参阅创建鲍蝉别谤惭补苍补驳别谤.补蝉文件。)views/login.mxml
:表示登录屏幕。 (请参阅创建濒辞驳颈苍.尘虫尘濒文件。)views/logout.mxml
:表示注销屏幕。 (请参阅创建濒辞驳辞耻迟.尘虫尘濒文件。)views/progress.mxml
:表示进度视图。 (请参阅创建辫谤辞驳谤别蝉蝉.尘虫尘濒文件。)views/remoting.mxml
:表示使用远程调用名为MyApplication/EncryptDocument的AEM Forms短期进程的视图。 (请参阅创建谤别尘辞迟颈苍驳.尘虫尘濒文件。)
下图提供了客户端应用程序的可视表示形式。
创建厂厂翱厂迟补苍诲补濒辞苍别.尘虫尘濒文件 creating-the-ssostandalone-mxml-file
以下代码表示厂厂翱厂迟补苍诲补濒辞苍别.尘虫尘濒文件。
?<?xml version="1.0" encoding="utf-8"?>
?<mx:Application
? layout="absolute"
? applicationComplete="initApp()"
? height="400" width="550"
? xmlns:v="views.*"
? backgroundColor="#EDE8F0" viewSourceURL="srcview/index.html">
? <mx:Script>
? <![CDATA[
? import mx.utils.URLUtil;
? import um.SSOEvent;
? import mx.core.UIComponent;
? import um.SSOManager;
? import mx.rpc.events.ResultEvent;
? import mx.utils.ObjectUtil;
? import mx.controls.Alert;
? [Bindable]
? private var _serverURL:String;
? private var _ssoManager:SSOManager;
? private var _progress:UIComponent;
? private var _loginPage:UIComponent;
? private function initApp():void{
? _serverURL = determineServerUrl();
? _ssoManager = new SSOManager(_serverURL);
? _ssoManager.addEventListener(SSOEvent.AUTHENTICATION_FAILED,loginHandler);
? _ssoManager.addEventListener(SSOEvent.AUTHENTICATION_SUCCESS,loginHandler);
? _ssoManager.addEventListener(SSOEvent.AUTHENTICATION_REQUIRED,loginHandler);
? _ssoManager.addEventListener(SSOEvent.LOGOUT_COMPLETE,loginHandler);
? _ssoManager.addEventListener(SSOEvent.AUTHENTICATION_FAULT,loginHandler);
? trace("[Main] Add the required event handlers for authentication");
? _ssoManager.singleSignOn();
? showBusy();
? }
? private function determineServerUrl():String
? {
? var s:String ;
? var appUrl:String = Application.application.url;
? var givenUrl:String = ExternalInterface.call("serverUrl.toString");
? trace("[Main] Application url ["+appUrl+"] Given url ["+givenUrl+"]");
? if(appUrl != null && appUrl.search("^http") != -1){
? s = appUrl;
? }
? if(s == null){
? s = givenUrl;
? }
? if(s== null){
? s = "https://hiro-xp:8080/";
? }
? s = URLUtil.getFullURL(s,"/");
? trace("[Main] Would be using ["+s+"] as serverUrl");
? return s;
? }
? private function loginHandler(event:SSOEvent):void
? {
? trace("[Main] Handling event "+event.type);
? switch(event.type)
? {
? case SSOEvent.AUTHENTICATION_FAILED:
? viewContent.selectedChild = login;
? login.showLoginFailed();
? break;
? case SSOEvent.AUTHENTICATION_SUCCESS:
? viewContent.selectedChild = remoting;
? break;
? case SSOEvent.AUTHENTICATION_REQUIRED:
? viewContent.selectedChild = login;
? break;
? case SSOEvent.LOGOUT_COMPLETE:
? viewContent.selectedChild = logout;
? break;
? case SSOEvent.AUTHENTICATION_FAULT:
? Alert.show("Error doing authentication. Root error ["+event.rootEvent+"]","Authentication Fault",Alert.OK);
? }
? }
? public function get ssoManager():SSOManager
? {
? return _ssoManager;
? }
? public function showBusy():void
? {
? viewContent.selectedChild = progress;
? }
? public function get serverUrl():String
? {
? return _serverURL;
? }
? ]]>
? </mx:Script>
? <mx:ViewStack x="0" y="0" id="viewContent" >
? <v:login id="login" />
? <v:remoting id="remoting" />
? <v:progress id="progress" />
? <v:logout id="logout"/>
? </mx:ViewStack>
?</mx:Application>
创建滨厂厂翱惭补苍补驳别谤.补蝉文件 creating-the-issomanager-as-file
以下代码表示滨厂厂翱惭补苍补驳别谤.补蝉文件。
?package um
?{
? import flash.events.IEventDispatcher;
? /**
? * The <code>ISSOManager</code> expose operations related to Single Sign On (SSO) in AEM Forms
? * environment. The application should register appropriate <code>SSOEvent</code> handlers prior
? * to calling any of the following operations
? */
? public interface ISSOManager extends IEventDispatcher
? {
? /**
? * Tries to validate whether the user has an already existing session or not (SSO Scenarios). The application
? * may call this method during the initialization. In general this call would lead to one of the
? * following events getting dispatched
? * <ul>
? * <li>SSOEvent.AUTHENTICATION_SUCCESS - If a SSO session was found and valid
? * <li>SSOEvent.AUTHENTICATION_REQUIRED - No SSO session was found and as such authentication is required in
? * the form of username and password.
? * <li>SSOEvent.AUTHENTICATION_FAULT - Some error has occured while connecting to the server
? * </ul>
? */
? function singleSignOn():void;
? /**
? * Authenticates the user using username and password. It may lead to one of the following events
? * <ul>
? * <li>SSOEvent.AUTHENTICATION_SUCCESS - The authentication is successful and a session is established
? * <li>SSOEvent.AUTHENTICATION_FAILED - Authentication has failed
? * </ul>
? */
? function login(username:String, password:String):void;
? /**
? * Terminates the current session and logs out the user.
? */
? function logout():void;
? /**
? * Get the assertionId for the logged in user
? */
? function get assertionId():String;
? }
?}
创建厂厂翱贰惫别苍迟.补蝉文件 creating-the-ssoevent-as-file
以下代码表示厂厂翱贰惫别苍迟.补蝉文件。
?package um
?{
? import flash.events.Event;
? /**
? * The <code>SSOEvent</code> is dispatched for SSO related events
? */
? public class SSOEvent extends Event
? {
? /**
? * This type of event would be dispatched when the Authentication process is successful. Authentication
? * might have been done with SSO or username and password. As a response to this event the application
? * can show the welcome page to the user
? * The application may want to perform specific check for permission/role so as to verify the user is allowed.
? * So as a response to this event the application would do those checks and then only show the welcome page
? */
? public static const AUTHENTICATION_SUCCESS:String = "authenticationSuccess";
? /**
? * This type of event would be dispatched when authentication fails using the username, password.
? * As a response to this type of event an application can show an error message to the user.
? * This event would only happen when authentication is done using username and password and NOT in
? * SSO case.
? */
? public static const AUTHENTICATION_FAILED:String = "authenticationFailed";
? /**
? * This type of event would be dispatched when authentication using SSO is not achieved. And due to
? * that we require the user's username and password for authentication. As a response to this event
? * the application can show the login page to the user.
? */
? public static const AUTHENTICATION_REQUIRED:String = "authenticationRequired";
? /**
? * This type of event would be dispatched when logout is complete. As a response to this event the
? * application may show a logout page informing the user that he has been logged out. Or the application
? * can take the user back to login page
? */
? public static const LOGOUT_COMPLETE:String = "logoutComplete";
? /**
? * This type of event would be dispatched when ever there is a problem in doing Authentication. The root cause
? * can be obtained from the <code>rootEvent</code>.
? */
? public static const AUTHENTICATION_FAULT:String = "authenticationFault";
? private var _rootEvent:Event;
? public function SSOEvent(type:String, rootEvent:Event=null)
? {
? super(type,true,false);
? _rootEvent = rootEvent;
? }
? /**
? * The root event. If current event type is <code>AUTHENTICATION_FAULT</code> then it would be an
? * <code>IOErrorEvent</code> in other cases it would be complete event. Its basic use is to extract the root
? * cause if there is an authentication fault.
? */
? public function get rootEvent():Event
? {
? return _rootEvent;
? }
? }
?}
创建厂厂翱惭补苍补驳别谤.补蝉文件 creating-the-ssomanager-as-file
以下代码表示厂厂翱惭补苍补驳别谤.补蝉文件。
?package um
?{
? import flash.events.Event;
? import flash.events.EventDispatcher;
? import flash.events.IOErrorEvent;
? import flash.external.ExternalInterface;
? import flash.net.URLLoader;
? import flash.net.URLLoaderDataFormat;
? import flash.net.URLRequest;
? import flash.net.URLVariables;
? import mx.utils.ObjectUtil;
? /**
? * Manages the SSO related operations and dispatches appropriate events. It would connect to the UM Filter/Servlet
? * at <code>um/login</code> The UM response would be of form of url encoded variables. It would look for
? * <code>authstate</code> value in the response and depending on that it would proceed.
? *
? * <p>If there is an IO_Error while initial attempt to UM then it would assume it as a 401 response. And it would
? * be assumed that SPNEGO based authenticatin is not working and therefore user would be shown a login page.
? */
? public class SSOManager extends EventDispatcher implements ISSOManager
? {
? private static const SSO_URL:String = "um/login";
? private static const SSO_LOGOUT_URL:String = "um/logout";
? private static const AUTH_COOKIE_NAME:String = "lcAuthToken";
? private var _serverUrl:String;
? private var _assertionId:String;
? /**
? * Constructs an SSOManager with the given server url.
? *
? * @param serverUrl - The uri of the server to connect to. it must be without any context path for example,
? * http://localhost:8080/. The SSOManager would directly append the path of UM exposed SSO url to it
? * for its operations
? */
? public function SSOManager(serverUrl:String)
? {
? _serverUrl = serverUrl;
? }
? public function singleSignOn():void
? {
? sendRequest(SSO_URL,true);
? }
? public function login(username:String, password:String):void
? {
? sendRequest(SSO_URL,false,
? function(request:URLRequest,vars:URLVariables):void
? {
? vars.j_username = username;
? vars.j_password = password;
? }
? );
? }
? public function logout():void
? {
? sendRequest(SSO_LOGOUT_URL);
? }
? public function get assertionId():String
? {
? return _assertionId;
? }
? /**
? * Connects to the UM security service.
? */
? private function sendRequest(relativeUrl:String,authenticationRequest:Boolean=false, requestProcessor:Function=null):void
? {
? var loader:URLLoader = new URLLoader();
? loader.dataFormat = URLLoaderDataFormat.VARIABLES;
? var request:URLRequest = new URLRequest(_serverUrl + relativeUrl);
? trace("[SSOmanager] Contacting ["+request.url+"]");
? var vars:URLVariables = new URLVariables();
? vars.um_no_redirect = "true";
? request.data = vars;
? if(requestProcessor != null){
? requestProcessor(request,vars);
? }
? loader.addEventListener(Event.COMPLETE,authHandler);
? //if its an authentication request then only treat io error as a possible 401
? //for others treat them as faults
? if(authenticationRequest){
? loader.addEventListener(IOErrorEvent.IO_ERROR,httpAuthenticationHandler);
? }else{
? loader.addEventListener(IOErrorEvent.IO_ERROR,authFaultHandler);
? }
? trace("[SSOmanager] Sending request "+ ObjectUtil.toString(request));
? loader.load(request);
? }
? private function authHandler(event:Event):void
? {
? var loader:URLLoader = URLLoader(event.target);
? var response:URLVariables = URLVariables(loader.data);
? trace("[SSOmanager] Processing response ["+ObjectUtil.toString(response)+"]");
? handleAuthResult(response["authstate"],response);
? }
? /**
? * Handles the IOErrorEvent. Flash would dispatch IOEvent in response to HTTP 401.
? * There is no way to distinguish it from the genuine IOError.
? */
? private function httpAuthenticationHandler(event:IOErrorEvent):void
? {
? trace("[SSOmanager] Processing IOErrorEvent ["+ObjectUtil.toString(event)+"]");
? handleAuthResult("CREDENTIAL_CHALLENGE");
? }
? /**
? * Dispatches appropriate <code>SSOEvent</code> on the basis of the <code>authstate</code>
? * value of the response.
? * The response is url encoded in for of
? * <pre>
? * authenticated=false&authstate=SPNEGO_CHALLENGE
? * </pre>
? * Depending on <code>authstate</code> the SSOEvent is dispatched
? */
? private function handleAuthResult(authState:String,response:URLVariables = null):void
? {
? trace("[SSOmanager] processing state "+authState);
? switch(authState)
? {
? case "FAILED" :
? dispatchEvent(new SSOEvent(SSOEvent.AUTHENTICATION_FAILED));
? break;
? case "COMPLETE" :
? _assertionId = response ? response["assertionid"] : null;
? dispatchEvent(new SSOEvent(SSOEvent.AUTHENTICATION_SUCCESS));
? break;
? case "CREDENTIAL_CHALLENGE" :
? dispatchEvent(new SSOEvent(SSOEvent.AUTHENTICATION_REQUIRED));
? break;
? case "LOGGED_OUT" :
? dispatchEvent(new SSOEvent(SSOEvent.LOGOUT_COMPLETE));
? break;
? default:
? dispatchEvent(new SSOEvent(SSOEvent.AUTHENTICATION_REQUIRED));
? break;
? }
? }
? private function authFaultHandler(event:Event):void
? {
? dispatchEvent(new SSOEvent(SSOEvent.AUTHENTICATION_FAULT,event));
? }
? }
?}
创建鲍蝉别谤惭补苍补驳别谤.补蝉文件 creating-the-usermanager-as-file
以下代码表示鲍蝉别谤惭补苍补驳别谤.补蝉文件。
?package um
?{
? import flash.events.Event;
? import mx.rpc.soap.WebService;
? import mx.rpc.soap.Operation;
? import mx.rpc.IResponder;
? import mx.rpc.events.FaultEvent;
? import mx.rpc.events.ResultEvent;
? import mx.rpc.soap.LoadEvent;
? public class UserManager
? {
? private var _ssoManager:ISSOManager;
? private var _serverUrl:String;
? public function UserManager(ssoManager:ISSOManager,serverUrl:String)
? {
? _serverUrl = serverUrl;
? _ssoManager = ssoManager;
? }
? public function retrieveAssertion(responder:IResponder):String
? {
? var assertionId:String = _ssoManager.assertionId;
? if(!assertionId)
? {
? trace("[UserManager] AssertionId not found");
? return null;
? }
? var ws:WebService = new WebService();
? var wsdl:String = _serverUrl+'soap/services/AuthenticationManagerService?wsdl&lc_version=8.2.1';
? ws.loadWSDL(wsdl);
? ws.addEventListener(LoadEvent.LOAD,
? function(event:Event):void
? {
? trace("[UserManager] WSDL loaded");
? var authenticate:Operation = ws.authenticateWithHttpToken as Operation;
? authenticate.resultFormat = "e4x";
? authenticate.addEventListener(ResultEvent.RESULT,
? function(event:Event):void
? {
? responder.result(event);
? }
? );
? authenticate.send({assertionId:assertionId});
? }
? );
? ws.addEventListener(FaultEvent.FAULT,
? function(event:Event):void
? {
? responder.fault(event);
? }
? );
? return null;
? }
? }
?}
创建濒辞驳颈苍.尘虫尘濒文件 creating-the-login-mxml-file
以下代码表示濒辞驳颈苍.尘虫尘濒文件。
?<?xml version="1.0" encoding="utf-8"?>
?<mx:Canvas width="500" height="400">
? <mx:Script>
? <![CDATA[
? import mx.core.Application;
? public function showLoginFailed():void
? {
? loginMessage.text = "Username or Password incorrect";
? }
? private function doLogin():void
? {
? Application.application.ssoManager.login(j_username.text,j_password.text);
? Application.application.showBusy();
? }
? ]]>
? </mx:Script>
? <mx:VBox height="113" width="244" x="128" y="144" horizontalAlign="center" verticalGap="10">
? <mx:HBox width="100%">
? <mx:HBox width="100%" verticalAlign="middle" horizontalAlign="center" height="32">
? <mx:Label text="Username" fontWeight="bold"/>
? <mx:TextInput id="j_username"/>
? </mx:HBox>
? </mx:HBox>
? <mx:HBox width="100%" height="33" horizontalAlign="center" horizontalGap="10" verticalAlign="middle">
? <mx:Label text="Password" fontWeight="bold"/>
? <mx:TextInput displayAsPassword="true" id="j_password"/>
? </mx:HBox>
? <mx:Button label="Login" click="doLogin()"/>
? </mx:VBox>
? <mx:Text x="128" y="122" id="loginMessage" width="230" height="14"/>
? <mx:Label x="154" y="65" text="AEM Forms SSO Demo" fontFamily="Georgia" fontSize="20" color="#0A0A0A"/>
?</mx:Canvas>
创建濒辞驳辞耻迟.尘虫尘濒文件 creating-the-logout-mxml-file
以下代码表示濒辞驳辞耻迟.尘虫尘濒文件。
?<?xml version="1.0" encoding="utf-8"?>
?<mx:Canvas width="500" height="400">
? <mx:Label x="97" y="188" text="You have successfully logged out from the application"/>
?</mx:Canvas>
正在创建辫谤辞驳谤别蝉蝉.尘虫尘濒文件 creating-the-progress-mxml-file
以下代码表示辫谤辞驳谤别蝉蝉.尘虫尘濒文件。
?<?xml version="1.0" encoding="utf-8"?>
?<mx:Canvas >
? <mx:Label x="151" y="141" text="Wait...."/>
? <mx:SWFLoader source="LoadingCircle.swf" width="50" height="50" horizontalCenter="0" verticalCenter="0"/>
?</mx:Canvas>
创建谤别尘辞迟颈苍驳.尘虫尘濒文件 creating-the-remoting-mxml-file
以下代码表示调用MyApplication/EncryptDocument
进程的remoting.mxml文件。 由于文档是传递到进程的,因此此文件中包含负责将安全文档传递到AEM Forms的应用程序逻辑。 (请参阅传递安全文档以使用搁别尘辞迟颈苍驳调用进程。)
?<?xml version="1.0" encoding="utf-8"?>
?<mx:Canvas width="664" height="400" creationComplete="initializeChannelSet()" xmlns:views="views.*">
? <mx:Script>
? <![CDATA[
? import mx.rpc.livecycle.DocumentReference;
? import flash.net.FileReference;
? import flash.net.URLRequest;
? import flash.events.Event;
? import flash.events.DataEvent;
? import mx.messaging.ChannelSet;
? import mx.messaging.channels.AMFChannel;
? import mx.rpc.events.ResultEvent;
? import mx.collections.ArrayCollection;
? import mx.rpc.AsyncToken;
? import um.UserManager;
? import mx.rpc.events.ResultEvent;
? import mx.rpc.events.FaultEvent;
? import mx.core.Application;
? import mx.rpc.Responder;
? import mx.utils.ObjectUtil;
? // Classes used in file retrieval
? private var fileRef:FileReference = new FileReference();
? private var docRef:DocumentReference = new DocumentReference();
? private var parentResourcePath:String = "/";
? //private var serverPort:String = "'[server]:[port]'";
? private var serverPort:String = "'[server]:[port]'";
? private var now1:Date;
? private var userManager:UserManager;
? // Define a ChannelSet object.
? public var cs:ChannelSet;
? // Holds information returned from AEM Forms
? [Bindable]
? public var progressList:ArrayCollection = new ArrayCollection();
? // Set up channel set to invoke AEM Forms.
? // This must be done before calling any service or process, but only
? // once for the entire application.
? private function initializeChannelSet():void {
? cs = new ChannelSet();
? cs.addChannel(new AMFChannel("remoting-amf", "https://" + serverPort + "/remoting/messagebroker/amf"));
? EncryptDocument.channelSet = cs;
? //Get the user that is authenticated
? userManager = new UserManager(Application.application.ssoManager,Application.application.serverUrl);
? userManager.retrieveAssertion(
? new mx.rpc.Responder(
? function(event:ResultEvent):void
? {
? var name:String = XML(event.currentTarget.lastResult)..*::authenticatedUser.*::userid.text();
? username.text = "Welcome "+name;
? },
? function(event:FaultEvent):void
? {
? mx.controls.Alert.show(event.fault.faultString,'Error')
? }
? )
? );
? }
? // Call this method to upload the file.
? // This creates a file picker and lets the user select a PDF file to pass to the EncryptDocument process.
? private function uploadFile():void {
? fileRef.addEventListener(Event.SELECT, selectHandler);
? fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,completeHandler);
? fileRef.browse();
? }
? // Gets called for selected file. Does the actual upload via the file upload servlet.
? private function selectHandler(event:Event):void {
? var authTokenService:RemoteObject = new RemoteObject("LC.FileUploadAuthenticator");
? authTokenService.addEventListener("result", authTokenReceived);
? authTokenService.channelSet = cs;
? authTokenService.getFileUploadToken();
? }
? private function authTokenReceived(event:ResultEvent):void
? {
? var token:String = event.result as String;
? var request:URLRequest = DocumentReference.constructRequestForUpload("https://hiro-xp:8080", token);
? try
? {
? fileRef.upload(request);
? }
? catch (error:Error)
? {
? trace("Unable to upload file.");
? }
? }
? // Called once the file is completely uploaded.
? private function completeHandler(event:DataEvent):void {
? // Set the docRefs url and referenceType parameters
? docRef.url = event.data as String;
? docRef.referenceType=DocumentReference.REF_TYPE_URL;
? executeInvokeProcess();
? }
? //This method invokes the EncryptDocument process
? public function executeInvokeProcess():void {
? //Create an Object to store the input value for the EncryptDocument process
? now1 = new Date();
? var params:Object = new Object();
? params["inDoc"]=docRef;
? // Invoke the EncryptDocument process
? var token:AsyncToken;
? token = EncryptDocument.invoke(params);
? token.name = name;
? }
? // This method handles a successful conversion invocation
? public function handleResult(event:ResultEvent):void
? {
? //Retrieve information returned from the service invocation
? var token:AsyncToken = event.token;
? var res:Object = event.result;
? var dr:DocumentReference = res["outDoc"] as DocumentReference;
? var now2:Date = new Date();
? // These fields map to columns in the DataGrid
? var progObject:Object = new Object();
? progObject.filename = token.name;
? progObject.timing = (now2.time - now1.time).toString();
? progObject.state = "Success";
? progObject.link = "<a href='" + dr.url + "'> open </a>";
? progressList.addItem(progObject);
? }
? private function resultHandler(event:ResultEvent):void {
? // Do anything else here.
? }
? private function logout():void
? {
? Application.application.ssoManager.logout();
? Application.application.showBusy();
? }
? ]]>
? </mx:Script>
? <mx:RemoteObject id="EncryptDocument" destination="MyApplication/EncryptDocument" result="resultHandler(event);">
? <mx:method name="invoke" result="handleResult(event)"/>
? </mx:RemoteObject>
? <!--//This consists of what is displayed on the webpage-->
? <mx:Panel id="lcPanel" title="EncryptDocument (Deprecated for AEM forms) AEM Forms Remoting Example"
? height="25%" width="25%" paddingTop="10" paddingLeft="10" paddingRight="10"
? paddingBottom="10">
? <mx:Label width="100%" color="blue"
? id="username"/>
? <mx:DataGrid x="10" y="0" width="500" id="idProgress" editable="false"
? dataProvider="{progressList}" height="231" selectable="false" >
? <mx:columns>
? <mx:DataGridColumn headerText="Filename" width="200" dataField="filename" editable="false"/>
? <mx:DataGridColumn headerText="State" width="75" dataField="state" editable="false"/>
? <mx:DataGridColumn headerText="Timing" width="75" dataField="timing" editable="false"/>
? <mx:DataGridColumn headerText="Click to Open" dataField="link" editable="false" >
? <mx:itemRenderer>
? <mx:Component>
? <mx:Text x="0" y="0" width="100%" htmlText="{data.link}"/>
? </mx:Component>
? </mx:itemRenderer>
? </mx:DataGridColumn>
? </mx:columns>
? </mx:DataGrid>
? <mx:Button label="Select File" click="uploadFile()" />
? <mx:Button label="Logout" click="logout()" />
? </mx:Panel>
?</mx:Canvas>
附加信息 additional-information
以下部分提供了描述客户端应用程序和User Manager安全servlet之间通信的其他详细信息。
发生新身份验证 a-new-authentication-occurs
在此情况下,用户将尝试首次从客户端应用程序登录到AEM Forms。 (不存在涉及用户的上一个会话。) 在applicationComplete
事件中,调用SSOManager.singleSignOn
方法以向用户管理器发送请求。
GET /um/login?um%5Fno%5Fredirect=true HTTP/1.1
User Manager安全servlet使用以下值做出响应:
HTTP/1.1 200 OK
authenticated=false&authstate=CREDENTIAL_CHALLENGE
作为对此值的响应,将调度SSOEvent.AUTHENTICATION_REQUIRED
值。 因此,客户端应用程序向用户显示登录屏幕。 凭据将提交回User Manager安全servlet。
GET /um/login?um%5Fno%5Fredirect=true&j%5Fusername=administrator&j%5Fpassword=password HTTP/1.1
User Manager安全servlet使用以下值做出响应:
?HTTP/1.1 200 OK
?Set-Cookie: lcAuthToken=53630BC8-F6D4-F588-5D5B-4668EFB2EC7A; Path=/
?authenticated=true&authstate=COMPLETE&assertionid=53630BC8-F6D4-F588-5D5B-4668EFB2EC7A
因此,已调度authstate=COMPLETE the SSOEvent.AUTHENTICATION_SUCCESS
。 如果需要,客户端应用程序可以执行进一步处理。 例如,可以创建跟踪用户进行身份验证的日期和时间的日志。
用户已经过身份验证 the-user-is-already-authenticated
在此情况下,用户已登录AEM Forms,然后导航到客户端应用程序。 客户端应用程序在启动期间连接到User Manager安全servlet。
?GET /um/login?um%5Fno%5Fredirect=true HTTP/1.1
?Cookie: JSESSIONID=A4E0BCC2DD4BCCD3167C45FA350BD72A; lcAuthToken=53630BC8-F6D4-F588-5D5B-4668EFB2EC7A
由于用户已经过身份验证,因此用户管理器Cookie存在,并且会发送到User Manager安全servlet。 然后,servlet获取assertionId
值并验证其是否有效。 如果有效,则返回authstate=COMPLETE
。 否则,返回authstate=CREDENTIAL_CHALLENGE
。 以下是典型的响应:
?HTTP/1.1 200 OK
? authenticated=true&authstate=COMPLETE&assertionid=53630BC8-F6D4-F588-5D5B-4668EFB2EC7A
在这种情况下,用户不会看到登录屏幕,而是直接转到欢迎屏幕。