3

I am in the process to try to separate out the mobile from the desktop part of my application and thought I try DDP.connect as a means for the mobile application to share data with the desktop application.

My first hurdle is concerning Meteor internal collections and publications.

How am I supposed to authenticate users? I know I can call the login method to authenticate a user, but that still doesn't give me all the other nice reactive features I am used to with Meteor.users

Is this supposed to work, and if so what is the pattern.

Thanks

Jamgold
  • 1,716
  • 1
  • 14
  • 18

4 Answers4

5

This is what integrated completely with a remote server (except code refresh, which forgets user session)

if (Meteor.isClient) {
 Meteor.connection = DDP.connect('http://remote.site.com');
 Accounts.connection = Meteor.connection;
 Meteor.users = new Meteor.Collection('users');
 SomeCollection = new Meteor.Collection('remote_collection');
 Meteor.connection.subscribe('users');
 Meteor.connection.subscribe('remote_collection');
 // rest if the code just as always
}

This way you can use login directly (via accounts-base, accounts-passed, etc) and don't need to call a login method. Just add accounts-ui and include {{>loginButtons}} and it works

Jamgold
  • 1,716
  • 1
  • 14
  • 18
5

I had a similar problem. I wanted to have two different front-ends (although both are for desktop) to the same back-end, so they could use same database, publications, and methods. After looking through Meteor's source code (version 1.1.0.3) I've managed to do this as follows.

1) Start back-end server project.

$ meteor --port 3100

2) In front-end project(s), put following in server/server.config.js.

var backendUrl = process.env.BACKEND_URL;

if (backendUrl) {
    __meteor_runtime_config__.BACKEND_URL = backendUrl;
    __meteor_runtime_config__.ACCOUNTS_CONNECTION_URL = backendUrl;

    console.log('config', __meteor_runtime_config__);
}

3) In front-end project(s), put following in client/lib/client.connection.js. APS is just a namespace for my application. Be sure to have this loaded before you use subscriptions or methods (that's why it's in lib folder).

if (typeof APS == 'undefined') APS = {};

var backendUrl = __meteor_runtime_config__.BACKEND_URL;

if (backendUrl) {
    APS.backendConnection = DDP.connect(backendUrl);

    Meteor.connection = APS.backendConnection;

    _.each(['subscribe', 'methods', 'call', 'apply', 'status', 'reconnect', 'disconnect'], function(name) {
        Meteor[name] = _.bind(Meteor.connection[name], Meteor.connection);
    });

    console.log('connected to backend', APS.backendConnection);
}

4) Start front-end server with BACKEND_URL environment variable pointing to your back-end server.

$ BACKEND_URL=http://192.168.33.10:3100 meteor

That's all. Refresh on client works OK. And we don't have to fiddle with Accounts.*.


UPDATE: Just found a problem with my solution. When calling server methods, this.userId is always null. This is because Meteor.connection and Accounts.connection were two separate connections, despite to the same BACKEND_URL. Upon authentication, user ID gets associated only with the latter. Fixed client.connection.js is as follows.

if (typeof APS == 'undefined') APS = {};

var backendUrl = __meteor_runtime_config__.BACKEND_URL;

if (backendUrl) {
    APS.originalConnection = Meteor.connection;

    // Accounts is already connected to our BACKEND_URL
    APS.backendConnection = Accounts.connection;
    // Reusing same (authenticated) connection for method calls and subscriptions
    Meteor.connection = APS.backendConnection;

    _.each(['subscribe', 'methods', 'call', 'apply', 'status', 'reconnect', 'disconnect'], function(name) {
        Meteor[name] = _.bind(Meteor.connection[name], Meteor.connection);
    });

    console.log('Connected to backend', APS.backendConnection);
}
vgrechka
  • 51
  • 1
  • 3
2

You can authenticate using code like this:

var connection = DDP.connect("<url>")

To authenticate

connection.call("login", {"password":"qwerty","user":{"username":"user_1"}});

to get the user, add this on the other server)

Meteor.methods({
    whoami: function() { return Meteor.user() }
});

Then you can run further commands as if you were authenticated, like this to get who's logged in

console.log(connection.call("whoami");
Tarang
  • 75,157
  • 39
  • 215
  • 276
  • I found that answer and did that, but afterwards there was no Meteor.user object. How am I supposed to access the {currentUser}? – Jamgold Feb 12 '15 at 23:43
  • I see, thanks for updating the answer. What this means it that programming patterns in regards to authentication and users would be completely different from a "local" meteor. – Jamgold Feb 13 '15 at 15:24
  • @Akshat I have to use `Meteor.user()` on different server for particular method. How do I send `Meteor.user()` values? Is secure to send user values as a parameter. – Ramesh Murugesan Jul 15 '16 at 07:26
0

User account creation/Authentication:

  1. In client.js, create a DDP connection and set it to Accounts.connection

    Accounts.connection = Meteor.remoteConnection;

  2. Create an Accounts.users collection in the client and subscribe its contents from the external server as below.

    Accounts.users = new Meteor.Collection('users', {connection: Meteor.remoteConnection});

    Meteor.remoteConnection.subscribe('users');

  3. Now call the login method required as below and set the token returned in the localStorage. This works for all the internal clicks and routing.

    Meteor.loginWithPassword(login_email, login_password, function(err) { submit_button.button("reset"); if (err) { console.log(err); pageSession.set("errorMessage", err.message); return false; }else{ console.log("logged in as "+Meteor.userId()); var token = Accounts._storedLoginToken(); localStorage.setItem('_storedLoginToken', token); } });

  4. The problem with the above code is that, the token is reset after every manual client refresh. The result object contains the below signed in information. We have to take the token and login with token for every external client refresh.

    id:"5RigABaSzbARHv9ZD" token:"MItg8P59gsl_T5OXtaWRSjUnETqzns0hGEV26xWYxj7" tokenExpires:Thu Jul 20 2017 12:46:31 GMT+0530 (India Standard Time)

  5. In client.js, start-up call the loginwithtoken function with the returned token as below, whenever there is no user available.

    var user = Meteor.user(); var token = localStorage.getItem('_storedLoginToken'); if(user==null){ console.log("Token"+token +user); if(token) Meteor.loginWithToken(token, function(err){ // this is going to throw error if we logged out if(!err) { console.log('logged in !!!! ',token); } }); }

  6. Meteor throws an error while logging in with the token,

    Error logging in with token: Error: You've been logged out by the server. Please log in again. [403]

  7. To overcome this issue, we have to write a tracker function to track the logged in session and login again if required. This is basically a hack suggested in meteor forums.

    Tracker.autorun(function () { var user = Meteor.user(); var token = localStorage.getItem('_storedLoginToken'); if(user==null){ console.log("Token"+token +user); if(token) Meteor.loginWithToken(token, function(err){ // this is going to throw error if we logged out if(!err) { console.log('logged in !!!! ',token); } }); } });

  8. Reset the localStorage if user navigates to the login path. In Layout.js,

    if(path=='/login') localStorage.setItem('_storedLoginToken',null);