Hello there! Newbie talking...
I built an app that will consume a REST webservice (buitl in Rails) through Rhoconnect. Once I cannot controll sessions in the webservice, I authenticate each requests checking a token sent in its' header. My question is:
* I will store the user's token in the Rhodes app, so I need to send it as a parameter to Rhoconnect. How can I do that?
* When I receive the token param in Rhoconnect, how do I insert it in the header of the request I will send to webservice?
Thanks in advance.
Hi Daniel
You can send the parameters to rhoconnect app by passing them in query string as:
variable= '[{"value":"'+$sessionID+'"}]'
SyncEngine.dosync_source(ModelName.get_source_name,false,"query=#{variable}")
Here you can replace the variable with your variable name in which you have stored the session id. In query value is always send as a hash in rhoconnect application.
You will get these values in the query method of your source adapter.
There you have to parse the values to get the hash like:
@data = JSON.parse("#{params}")
#fetching the value from array
@data1 = @data[0]
You will get the hash in @data1 so you can use it easily.
And will you please tell me which type of web services are you using (get or post) so that i will be able to help you for your second scenario.
Thanks
Mohit Raheja
Points: 1
You voted ‘up’
Thanks Mohit!
First, where do I put this code "SyncEngine.dosync_source"? In the Rhodes' model? Sorry, I have few experience developing in Rhodes.
Second, I use the webservice to GETs and POSTs, but I check in each request (for both) the 'token' parameter, so that I can authenticate the user which is requesting the action.
Points: 0
You voted ‘up’
Hi Daniel
Right now, how you are calling your source adapter? You want to send the token on some user action or in auto sync process?
Along with that, if possible please the code of your controller file so that i will be able to help you.
And for authenticating the user, are you logging in your rhoconnect application with the same user with which you have logged in into your back-end application or are you just bypassing the rhoconnect login?
Thanks
Mohit Raheja
Points: 0
You voted ‘up’
Hi, Mohit. Thank you for clearing my doubts.
I haven't changed the auto-generated rhodes code, except uncommenting the "enable sync" on model. So, I want to send the token to Rhoconnect in the auto sync process.
Here is the "controller.rb" file code:
require 'rho'
require 'rho/rhocontroller'
require 'rho/rhoerror'
require 'helpers/browser_helper'
class SettingsController < Rho::RhoController
include BrowserHelper
def index
@msg = @params['msg']
render
end
def login
@msg = @params['msg']
render :action => :login
end
def login_callback
errCode = @params['error_code'].to_i
if errCode == 0
# run sync if we were successful
WebView.navigate Rho::RhoConfig.options_path
SyncEngine.dosync
else
if errCode == Rho::RhoError::ERR_CUSTOMSYNCSERVER
@msg = @params['error_message']
end
if !@msg || @msg.length == 0
@msg = Rho::RhoError.new(errCode).message
end
WebView.navigate ( url_for :action => :login, :query => {:msg => @msg} )
end
end
def do_login
if @params['login'] and @params['password']
begin
SyncEngine.login(@params['login'], @params['password'], (url_for :action => :login_callback) )
@response['headers']['Wait-Page'] = 'true'
render :action => :wait
rescue Rho::RhoError => e
@msg = e.message
render :action => :login
end
else
@msg = Rho::RhoError.err_message(Rho::RhoError::ERR_UNATHORIZED) unless @msg && @msg.length > 0
render :action => :login
end
end
def logout
SyncEngine.logout
@msg = "You have been logged out."
render :action => :login
end
def reset
render :action => :reset
end
def do_reset
Rhom::Rhom.database_full_reset
SyncEngine.dosync
@msg = "Database has been reset."
redirect :action => :index, :query => {:msg => @msg}
end
def do_sync
SyncEngine.dosync
@msg = "Sync has been triggered."
redirect :action => :index, :query => {:msg => @msg}
end
def sync_notify
status = @params['status'] ? @params['status'] : ""
# un-comment to show a debug status pop-up
#Alert.show_status( "Status", "#{@params['source_name']} : #{status}", Rho::RhoMessages.get_message('hide'))
if status == "in_progress"
# do nothing
elsif status == "complete"
WebView.navigate Rho::RhoConfig.start_path if @params['sync_type'] != 'bulk'
elsif status == "error"
if @params['server_errors'] && @params['server_errors']['create-error']
SyncEngine.on_sync_create_error(
@params['source_name'], @params['server_errors']['create-error'].keys, :delete )
end
if @params['server_errors'] && @params['server_errors']['update-error']
SyncEngine.on_sync_update_error(
@params['source_name'], @params['server_errors']['update-error'], :retry )
end
err_code = @params['error_code'].to_i
rho_error = Rho::RhoError.new(err_code)
@msg = @params['error_message'] if err_code == Rho::RhoError::ERR_CUSTOMSYNCSERVER
@msg = rho_error.message unless @msg && @msg.length > 0
if rho_error.unknown_client?( @params['error_message'] )
Rhom::Rhom.database_client_reset
SyncEngine.dosync
elsif err_code == Rho::RhoError::ERR_UNATHORIZED
WebView.navigate(
url_for :action => :login,
:query => {:msg => "Server credentials are expired"} )
elsif err_code != Rho::RhoError::ERR_CUSTOMSYNCSERVER
WebView.navigate( url_for :action => :err_sync, :query => { :msg => @msg } )
end
end
end
end
Let's say that, right now, I'm bypassing the rhoconnect login. I'm just using the token to interact with the webservice.
Thank you very much!
Points: 0
You voted ‘up’
Hi Daniel,
Well i don't think so that you will be able to send the parameters in auto-sync. For sending the parameters in rhoconnect you have to do a manual-sync.
Do you want to authenticate the user while fetching the data from back-end?
Can you please give me a brief idea about your scenario?
Thanks
Mohit Raheja
Points: 0
You voted ‘up’
I have an api built in Rails, with which I interact via JSON. Initially I
did it to interact with a desktop app. In this api, I'm not able to login
once and keep the session alive until the client is disconnected. So I did
the following: the user do login in the back-end and, if sucessful, the
service's response send a token to the desktop app. Once the app has the
token, it can request GETs and POSTs to the service sending the token in
header, no need to authenticate again and again. The back-end check the
token and authenticate it's own way. If the token is valid, then it
executes the requested action.
That's what I want to do with my rhodes app, the differences are that the
user will authenticate the app only once. I will store the token to each
user locally. So he will login (locally) and if the login is sucessful, it
will be able to sync the data with rhoconnect only passing the token in
each trigered sync.
In resume, I need to pass this token to Rhoconnect and in Rhoconnect I need
to add this param to the header of request to back-end in order to get the
JSON objects.
Is it clear?
Thank you very much.
2013/4/23 Mohit Raheja <motorola-dev@motorola-dev.hosted.jivesoftware.com>
Points: 0
You voted ‘up’
Hi Daniel
Thanks for the summary. I will suggest if you are getting the token from the back-end itself then don't pass it to the rhodes application rather store it in the rhoconnect application( i.e in redis server) and at the time a sync is triggered you can easily fetch the token from the rhoconnect application.
You can store the data in rhoconnect application as:
Store.put_value("userName","#{@sessionID}")
and you can fetch the values from there as:
@id = Store.get_value("userName")
By doing this way you don't have to fetch your token id from rhodes application.
And for sending a token in the header you can send it inside the body part of web service.
For get type service you can do it as:
service_url = "#{$base}/MethodName?sessionID=" + @id
#get type service call
@res=RestClient.get(service_url,:content_type => :json)
For post type of service you can do:
service_url = "#{$base}/MethodName"
#body containing username
body = "#{@id}"
#post type service call
@res=RestClient.post(service_url,body.to_json,:content_type => :json)
Hope it helps
Thanks
Mohit Raheja
Points: 0
You voted ‘up’
Hi Mohit, thanks for the help. I will certainly consider this solution, but there's just two things I'd like you explain me, if you can.
First: For security reasons I don't pass the token in plain URL, like a parameter (?token='xxxxxxxxxx'). I include it in the header, so that it's invisible in logs or something. That's why I wish to include it in the header of the Rhoconnect GETs and POSTs request to the back-end, instead of appending it to the service_url. Any opinion?
Second: As you said, it's not possible to send params in the auto-sync from Rhodes to Rhoconnect, right? Because I had in mind the following scenario: To require to the user to connect directly to the service at the first time he opens the app in his device, an then he can get the validation token directly, and Rhodes can store it locally in the device. In the next time he open the app, it doesn't need validation again (because the token is already stored), that's why I'd wish to pass the token from Rhodes to Rhoconnect.
Thank you very much for all this help.
Points: 0
You voted ‘up’
Hi Daniel
Yeah sending the token inside the URL is not secure that's why post type services are proffered. You can go for the post type web service as it secure.
And let me try once for the token then i will get back to you regarding this issue, as i haven't faced such scenario till now.
Thanks
Mohit Raheja
Points: 0
You voted ‘up’
Hello Mohit Raheja,
I'm confronting the same dilemma as Daniel is.
It seems to me the solution you suggest is not working the way I and Daniel would like to, considering the following scenario:
I login with username1 on device 1.
This user does; @id = Store.put_value("userName") on rhoconnect.
So store value for UserName is now "username1".
Now username2 logs in on device 2.
This user also does; @id = Store.put_value("userName") on rhoconnect.
So store value for UserName is now "username2".
Now username1 updates a record and synchronise that.
He will sync with username2... Which is not correct.
Am I overlooking something?
Points: 0
You voted ‘up’