It is possible to not only place a login form in an external website, but to create an entire fronted for users to interact with Cyclos. At first glimpse, this can be great, but consider the following:
It is a very big effort to create a frontend, as there are several Cyclos services involved, and it might not be clear without a deep analysis on the API which service / method / parameters should be used on each case.
The API will change. Even if we try not to break compatibility, it is possible that changes between 4.x to 4.y will contain (sometimes incompatible) changes to the API.
You will always have a limited subset of the functionality Cyclos offers. You may think that only the very basic features are needed, there will inevitably be the need for more features, and the custom frontend will need to grow. By using Cyclos standard web, all this comes automatically.
Neverthless, some (large) organizations might find it is better to provide their users with a single, integrated interface. In that case the application server of that interface will be the only one interacting with Cyclos (i.e, users won't directly browse the Cyclos interface). The application will relay web service calls to Cyclos in behalf of users.
To accomplish that, it is needed to first login users in the same way as explained in the previous section. However, after the login is complete, instead of redirecting users to Cyclos, the application needs to store the session token, and probably the user id (as some operations requires passing the logged user id) – both data received after logging in – in a session (in the interface application server). Then, the next web service requests should be sent using that session token and client remote address, instead of the administrator credentials. The way of passing that data depends on the web service access type being used:
Java clients: Create another HttpServiceFactory, using a stateful HttpServiceInvocationData. Here is an example:
import java.util.List;
import org.cyclos.model.access.LoggedOutException;
import org.cyclos.model.access.channels.BuiltInChannel;
import org.cyclos.model.access.login.UserAuthVO;
import org.cyclos.model.banking.accounts.AccountWithStatusVO;
import org.cyclos.model.users.users.UserLocatorVO;
import org.cyclos.model.users.users.UserLoginDTO;
import org.cyclos.model.users.users.UserLoginResult;
import org.cyclos.server.utils.HttpServiceFactory;
import org.cyclos.server.utils.HttpServiceInvocationData;
import org.cyclos.services.access.LoginService;
import org.cyclos.services.banking.AccountService;
/**
* Cyclos web service example: logs-in an user via web services.
* This is useful when creating an alternative front-end for Cyclos.
*/
public class LoginUser {
public static void main(String[] args) throws Exception {
// This LoginService has the administrator credentials
LoginService LoginService = Cyclos.getServiceFactory().getProxy(LoginService.class);
// Another option is to use an access client to connect with the
// server (for the admin)
// To make it works you must:
// 1- create an access client
// 2- assign it to the admin (to obtain the activation code)
// 3- activate it making a HTTP POST to the server using this url:
// ROOT_URL/activate-access-client containing only the activation code
// as the body
// 4- put the token returned from the servlet as the parameter of the
// HttpServiceInvocationData.accessClient(...) method
// 5- comment the first line (that using user and password and
// uncomment the following two sentences
// HttpServiceInvocationData adminSessionInvocationData =
// HttpServiceInvocationData
// .accessClient("put_the_token_here");
// LoginService LoginService = Cyclos.getServiceFactory(
// adminSessionInvocationData).getProxy(LoginService.class);
String remoteAddress = "192.168.1.200";
// Set the login parameters
UserLoginDTO params = new UserLoginDTO();
UserLocatorVO locator = new UserLocatorVO(UserLocatorVO.PRINCIPAL, "c1");
params.setUser(locator);
params.setPassword("1234");
params.setRemoteAddress(remoteAddress);
params.setChannel(BuiltInChannel.MAIN.getInternalName());
// Login the user
UserLoginResult result = LoginService.loginUser(params);
UserAuthVO userAuth = result.getUser();
String sessionToken = result.getSessionToken();
System.out.println("Logged-in '" + userAuth.getUser().getDisplay()
+ "' with session token = " + sessionToken);
// Do something as user. As the session token is only valid per ip
// address, we need to pass-in the client ip address again
HttpServiceInvocationData sessionInvocationData =
HttpServiceInvocationData.stateful(sessionToken, remoteAddress);
// The services acquired by the following factory will carry on the
// user session data
HttpServiceFactory userFactory = Cyclos.getServiceFactory(sessionInvocationData);
AccountService accountService = userFactory.getProxy(AccountService.class);
List<AccountWithStatusVO> accounts =
accountService.getAccountsSummary(userAuth.getUser(), null);
for (AccountWithStatusVO account : accounts) {
System.out.println(account.getType()
+ ", balance: " + account.getStatus().getBalance());
}
// Logout. There are 2 possibilities:
// - Logout as administrator:
LoginService.logoutUser(sessionToken);
// - OR logout as own user:
try {
userFactory.getProxy(LoginService.class).logout();
} catch (LoggedOutException e) {
// already logged out
}
}
}
PHP clients: In the configuration file, instead of calling Cyclos\Configuration::setAuthentication($username, $password), call the following: Cyclos\Configuration::setSessionToken($sessionToken) and Cyclos\Configuration::setForwardRemoteAddress(true), which will automatically send the $_SERVER['REMOTE_ADDR'] value on requests.
WEB-RPC: If sending JSON requests directly, instead of passing the Authentication header with the username / password, pass the following headers: Session-Token and Remote-Address.