Closed 27leaves closed 7 years ago
How are you making the calls?
Right now, I just tried 2 things
// template
'<div>{{ cloudVersion | async }}</div>'
// Class: cloudVersion: Observable
2. With a service
```typescript
@Injectable()
export class AuthService {
constructor(private wampService: WampService) {}
login({ email, password }: Authenticate) {
return this.wampService.call('cloud.user.login', [], {
email,
password,
deviceId: 'PartnerPortal',
deviceName: 'PartnerPortal'
});
}
}
This gets called within an ngrx effect:
@Effect()
login$ = this.actions$
.ofType(Auth.LOGIN)
.map((action: Auth.Login) => action.payload)
.exhaustMap(auth =>
this.authService
.login(auth)
.map(result => new Auth.LoginSuccess({ user: {token: result.argskw.token} }))
.catch(error => of(new Auth.LoginFailure(error.args[0])))
);
Also, I'm not sure how your authentication is working. I would do something like this:
@Injectable()
export class WampService extends Client {
constructor() {
const url = (environment.production) ?
'wss://' + location.host + '/router/' :
'wss://mydevelopserver.com/router/';
super(url, 'gateway', {authmethods: ['ticket', 'other']});
this.onChallenge(challenge => {
const ticketMethod = challenge.filter((msg: ChallengeMessage) => msg.authMethod === 'ticket');
const otherMethod = challenge.filter((msg: ChallengeMessage) => msg.authMethod === 'other');
const userToken = store
.select(fromAuth.getUser)
.take(1)
.pluck('token');
const ticketToken = ticketMethod.flatMapTo(userToken);
const otherToken = otherMethod.flatMap((msg: ChallengeMessage) => {
// Do some other auth lookup
return http.get('http://lookup_token' + msg.extra).pluck('results', 'token');
});
return Observable.merge(ticketToken, otherToken);
});
}
}
Oh wow, that's much cleaner, thank you, I'll try to get smth like this to work :)
The thing is in our cloud implementation: When I have no token it means the user is not logged in. In this case the authmethods is empty.
That does complicate things a bit. What I would do is create a separate service for the wamp connection without authentication. When the user logs in, you can emit the token on a service that is a Subject:
login({email, password}: Authenticate) {
return this.noauthwamp.call('cloud.user.login', [], {
email,
password,
deviceId: 'PartnerPortal',
deviceName: 'PartnerPortal'
})
.map(r => r.args.token)
.do(TokenSubjectService);
}
And then your authentication would look like:
this.onChallenge(challenge => {
const ticketMethod = challenge.filter((msg: ChallengeMessage) => msg.authMethod === 'ticket');
const localToken = store
.select(fromAuth.getUser)
.take(1)
.filter(user => user)
.pluck('token');
// If there is a local token, that'll be used, otherwise it'll wait until TokenSubjectService reacts
const token = Observable.race(localToken, TokenSubjectService);
return ticketMethod.flatMapTo(token);
});
Ideally, you'd probably want the onChallenge
to trigger the login dialog, in which case you wouldn't need TokenSubjectService
. Your race
would look like (pseudo code):
this.onChallenge(challenge => {
const ticketMethod = challenge.filter((msg: ChallengeMessage) => msg.authMethod === 'ticket');
const localToken = store
.select(fromAuth.getUser)
.take(1)
.filter(user => user)
.pluck('token');
const remoteToken = loginDialog
.flatMap(({email, password}) => {
return this.noauthwamp.call('cloud.user.login', [], {
email,
password,
deviceId: 'PartnerPortal',
deviceName: 'PartnerPortal'
});
})
.map(r => r.args.token);
// If there is a local token, the dialog observable will be cancelled
const token = Observable.race(localToken, remoteToken);
return ticketMethod.flatMapTo(token);
});
Hi! I was able to simplify the authentication together with my backend dev, so now the auth is working!
@Injectable()
export class WampService extends Client {
constructor(private store: Store<fromAuth.State>) {
super(
(environment.production) ?
'wss://' + location.host + '/router/' :
'wss://mydevelopserver.com/router/',
'gateway', {
authmethods: ['ticket']
});
this.onChallenge(challenge => {
const ticketMethod = challenge.filter((msg) => msg.authMethod === 'ticket');
const token = store
.select(fromAuth.getUser)
.take(1)
.map(user => user.token);
return ticketMethod.flatMapTo(token);
});
}
}
Thanks for this!
However, I'm now back to my original problem. My discoveries so far:
@creat-or can you create a sample project that I can play around with?
So, finally I got something you can hopefully work with... I created a new repository here https://github.com/creat-or/thruway-minimal-example.
There I created 2 services. WampService
and WampTicketService
. One is without authentication, connecting to the crossbar demo https://demo.crossbar.io/votes/index.html and the other one connects to our service via 'anonymous' ticket.
Open the console to see the logs while using the example.
(Click on Banana/Chocolate/Lemon)
(Click on getVersionInfo)
@creat-or Thank you for your demo. It looks like it is a bug with thruway.js. If you make one off RPCs, the websocket connection should close when it has completed. That's not working properly. As a temporary workaround, you can hold the websocket connection open by subscribing to a topic:
constructor() {
super('wss://demo.crossbar.io/ws', 'crossbardemo');
this.topic('io.crossbar.demo.keepwsopen').subscribe();
}
Ah nice, that works as a workaround. Thank you, too!
this.topic('io.crossbar.demo.keepwsopen').subscribe();
This answer is gold! Tnx!!! Fixed same issue for me too!
Hi!
I'm still on trying to get this to run. Maybe it needs a little more documentation or it is a bug, but I currently have the problem that only the first call() will return results. Maybe you can guide me to get a proper setup? Thanks :)
My current setup: