Marionette JS multiple route ,controller and session management - backbone.js

So my Marionette application has folowing 2 routes and controllers
AuthRoute and AuthController for user login and logout
UserRoute and UserControler for user listing, new user and edit user
In AuthController when user login I need to save the user session somewhere so that it can be acceable to both these routes, So next time when user hits user listing page I can check for user session and then load the user listing page.
How can I achieve this?
Also, what will be the best way to check if user session is valid or not? My plan is to create a service which will return user details if the session is valid or else will return 401, but till the time service returns the response I can't load the route specific views.
Can someone help me on these?
Thanks in Advance
MSK

I usually save session data in a singleton Beckbone.Model referenced by the Marionette.Application.
Session Model:
var SessionModel = Backbone.Model.extend({
initialize: function () {
this.listenTo(this, 'change', function (model) {
// Manage cookies storage
// ex. using js.cookie
Cookies.set('session', model.toJSON(), {expires: 1});
});
},
checkAuth: function () {
...
},
login: function (user, password, remember) {
...
},
logout: function () {
...
}
});
Application:
var app = new Marionette.Application({
session: new SessionModel(),
...
})
app.reqres.setHandlers({
session: function () {
return app.session;
}
});
Then you can access session model from any point through "global channel":
Backbone.Wreqr.radio.channel('global').reqres.request('session').checkAuth()
So you can implement all your session procedures in the session model class that can be accessed from the whole application. Using cookies you will also save the user session in the browser.

If you use backend API for Backbone then:
How can I achieve this?
The best way for saving a user session is cookies. Use it for storing and retrieving the user authentication_token.
Also, what will be the best way to check if user session is valid or
not?
You have to store authentication_token on the backend side. For login, logout, signup you should iterate with your API.

Related

angularjs firebase authentication cookies are persistent into the next user session

The problem is when a user 1 has signed out, and once the user 2 signs in, either the info of the user 2 is not show, or the info of user 1 is still shown. Apparently the cookies from the first user still hang around and prevent the transition softly.
here is my signout controller, does anyone have any improvements on this?
app.controller("MysignOutCtrl", ["$scope",function ($scope) {
$scope.signOut = function () {
firebase.auth().signOut().then(function() {
console.log("Sign-out successful");
}, function(error) {
toastr.error(error.message, error.reason, { timeOut: 10000 });
})
};
}]);
add the localStorage.clear(); after signout.
If you use AngularFire, always use its wrapper methods to prevent some unexpected behaviors.
I would use $firebaseAuth().$signOut() method.
Firebase does not support multiple logged in users. If you loggin with second account, it overwrites existing user data.

Node API - How to link Facebook login to Angular front end?

Rewriting this question to be clearer.
I've used passport-facebook to handle login with facebook on my site.
My front end is in Angular so I know now need to understand whats the correct way of calling that api route. I already have several calls using Angular's $http service - however as this login with facebook actually re-routes the facebook page can i still use the usual:
self.loginFacebook = function )() {
var deferred = $q.defer();
var theReq = {
method: 'GET',
url: API + '/login/facebook'
};
$http(theReq)
.then(function(data){
deferred.resolve(data);
})
return deferred.promise;
}
or is it perfectly ok/secure/correct procedure to directly hit that URL in a window location:
self.loginFacebook = function (){
$window.location.href = API + '/login/facebook';
}
Furthermore, from this how do I then send a token back from the API? I can't seem to modify the callback function to do that?
router.get('/login/facebook/callback',
passport.authenticate('facebook', {
successRedirect : 'http://localhost:3000/#/',
failureRedirect : 'http://localhost:3000/#/login'
})
);
Thanks.
I was stacked on the same problem.
First part:
I allow in backend using cors and in frontend i use $httpProvider, like this:
angular.module('core', [
'ui.router',
'user'
]).config(config);
function config($httpProvider) {
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
};
The second part:
<span class="fa fa-facebook"></span> Login with facebook
This call my auth/facebook route that use passport to redirect to facebook page allowing a user to be authenticated.
If the user grant access, the callback /api/auth/facebook/callback is called and the facebook.strategy save the user with the profile data.
After saving the user, i create a special token with facebook token, id and email. This info is used to validate every time the user access to private states in the front.
My routes are something like this:
router.get('/facebook', passport.authenticate('facebook',
{ session: false, scope : 'email' }));
// handle the callback after facebook has authenticated the user
router.get('/facebook/callback',
passport.authenticate('facebook',
{session: false, failureRedirect: '/error' }),
function(req, res, next) {
var token = jwt.encode(req.user.facebook, config.secret);
res.redirect("/fb/"+token);
});
In frontend i catch the /fb/:token using a state and assign the token to my local storage, then every time the user go to a private section, the token is sent to backend and validate, if the validation pass, then the validate function return the token with the decoded data.
The only bad thing is that i don't know how to redirect to the previous state that was when the user click on login with facebook.
Also, i don't know how you are using the callback, but you need to have domain name to allow the redirect from facebook. I have created a server droplet in digitalocean to test this facebook strategy.
In the strategy you have to put the real domain in the callback function, like this:
callbackURL: "http://yourdomain.com/api/auth/facebook/callback"
In the same object where you put the secretId and clientSecret. Then, in your application in facebook developers you have to allow this domain.
Sorry for my english, i hope this info help you.
Depending on your front-end, you will need some logic that actually makes that call to your node/express API. Your HTML element could look like
<a class='btn' href='login/facebook'>Login</a>
Clicking on this element will make a call to your Express router using the endpoint of /login/facebook. Simple at that.

Firebase logout show Permission denied error.

So whenever I logout from Firebase, I got coupled
Error: permission_denied: Client doesn't have permission to access the desired data.
I understand it is because login session is terminated, some of my objects cannot access firebase data any more. But how can I disconnect this objects before logout?
For logout button in one of my Ionic View, it just call a firebase service:
function logout() {
auth.$unauth();
getCurrentUser();
};
function getCurrentUser() {
var authData = auth.$getAuth();
if (authData) {
$rootScope.userId = authData.uid;
$rootScope.currentUser = $firebaseObject(authRef.child("users").child(authData.uid));
return $rootScope.currentUser;
} else {
console.log("User is not login!");
$rootScope.userId = null;
$location.path("/auth/signin");
if ($rootScope.currentUser) {
$rootScope.currentUser.$destroy();
}
}
};
So I destroy the $rootScope.currentUser there. I use the same getCurrentUser for profile page. So the Error did not show up this way. But when in other views, which I have another $firebaseArray, and also another Ref.on("child_added", function(snap) with the same $firebaseObject. When I view the profile page, then this page with at least 3 firebase connection, I got 3 permission_denied Errors when I logout (logout button is on user profile page).
My question is, how do I disconnect this firebase connection before I logout? Is there a way disconnect ALL the firebase connection - no matter AngularFire or regular Firebase? So I can logout without worry about which firebase connection I have no close yet? Also, since the Logout button is in Profile scope and the others connection is in a different scope, I have no idea how to close the connection which is not even in the profile scope...
You need to destroy all the firebase references on logout.
Something like this.
In logout function.
function logout() {
auth.$unauth();
$rootScope.$broadcast('logout');
};
In controller
vm.profile = authService.profile(user.uid); // FirebaseObject Reference
vm.parties = partyService.getPartiesByUser(user.uid); // FirebaseArray Reference
$rootScope.$on('logout', function () {
vm.parties.$destroy();
vm.profile.$destroy();
});
well, i guess you have a button to logout.
so in your function logout() you'd first $destroy the data object, somehow wait (whichs' best practice i'm trying to figure out), and then authref.unauth();
i'd say
You need destroy the firebase ref for the object that you saved data previously. How?
Before, I initialize my var songs like:
this.songs = this.af.list('/songs');
When I signOut(), I should destroy the reference of the variable that I initialized so that I execute:
this.songs.$ref.off();
With this line, your problem

bacbkone router redirect if not authenticated

I am trying to implement a simple app that needs a login and user authentication. As I am new to backbone and marionette, I have been trying to follow the example for this tutorial: https://github.com/davidsulc/marionette-gentle-introduction
Generally I have set up a new app:
var App = new Marionette.Application({});
App.addRegions({
headerRegion : "#nav-region",
mainRegion : "#main-region"
});
App.navigate = function(route, options){
options || (options = {});
Backbone.history.navigate(route, options);
};
App.getCurrentRoute = function(){
return Backbone.history.fragment
};
App.on("start", function(){
if(Backbone.history){
Backbone.history.start();
}
});
And routers are defined in modules, e.g.:
App.module("ContentManagementApp", function(ContentManagementApp, App, Backbone, Marionette, $, _){
ContentManagementApp.Router = Marionette.AppRouter.extend({
appRoutes : {
"contentmanagement/:dsid(/:dspageclassid)": "showContentMananagement",
}
});
var API = {
showContentMananagement : function(dsid, dspageclassid){
// If not set, set to frontpage
ContentManagementApp.Show.Controller.showDSPage(dsid, dspageclassid);
App.execute("set:active:header", "contentmanagement");
},
};
App.on("contentmanagement:show", function(dsid, dspageclassid){
App.navigate("contentmanagement/" + dsid + "/" + dspageclassid);
API.showContentMananagement(dsid, dspageclassid);
});
App.addInitializer(function(){
new ContentManagementApp.Router({
controller : API
});
});
});
I would like to test if the user is logged and redirect to the login page when the app starts, but it seems like App.addInitializer is called before. Does it mean I have to do the check in each module, or can I get by it somehow?
How do you determine if the user is logged or not?
If it's a call to an API that could fail (due to the user being unauthenticated), it will probably return an HTTP error code 403. I usually do this using a global jQuery ajax.error() handler, I check if it's a 403 (Forbidden) for any of my normal API calls (model fetching and so on) and if it is, I redirect to a login url.
Otherwise, if you want to check for a cookie or similar, you should do it before calling Backbone.history.start(). Only start the app if the user is logged. :)
I just set this up in my app - in your backend when the user is logged in create a cookie/destroy it when they sign-out. Then I use the jquery-cookie-rails gem to access the cookie as $.cookie('cookie_name') and if it isn't there I route them to the signin path.
I would note - I also check to see if the user is signed on the backend when hitting different controller actions and route them appropriately. I just like the extra protection :).

Get email ID/username after login using Google+ API

I want to access the user_name/email_id of the user who logs onto my website using Google+ API. So far I have implemented the Google+ API and the return value is:
User Logged In This is his auth tokenya29.AHES6ZRWhuwSAFjsK9jYQ2ZA73jw9Yy_O2zKjmzxXOI8tT6Y
How can I use this to get the username/email id?
Specifically for retrieving an email address of an authenticated user, keep in mind that you will need to include the userinfo.email scope and make a call to the tokeninfo endpoint. For more information on this, see https://developers.google.com/+/api/oauth#scopes.
if you are correctly logged in, it's enough to call the Google+ api at this URL:
GET https://www.googleapis.com/plus/v1/people/me
where the userId has the special value me, to get all the information about the logged user. For more information see:
https://developers.google.com/+/api/latest/people/get
I'm adding a code sample to help others.
In this case the login operation is performed against Google requesting email, as well as user profile information like name,.... Once all this information is retrieved, a request to my own login service is performed:
function OnGoogle_Login(authResult) {
if (authResult['access_token']) {
gapi.client.load('oauth2', 'v2', function()
{
gapi.client.oauth2.userinfo.get().execute(function(userData)
{
$("#frmLoginGoogle input[name='id']").val(userData.id);
$("#frmLoginGoogle input[name='name']").val(userData.name);
$("#frmLoginGoogle input[name='email']").val(userData.email);
$.ajaxSetup({cache: false});
$("#frmLoginGoogle").submit();
});
});
}
}
$(document).ready(function() {
/** GOOGLE API INITIALIZATION **/
$.ajaxSetup({cache: true});
$.getScript("https://apis.google.com/js/client:platform.js", function() {
$('#btnLoginGoogle').removeAttr('disabled');
});
$("#btnLoginGoogle").click(function() {
gapi.auth.signIn({
'callback': OnGoogle_Login,
'approvalprompt': 'force',
'clientid': 'XXXXX.apps.googleusercontent.com',
'scope': 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
'requestvisibleactions': '',
'cookiepolicy': 'single_host_origin'
});
});
});

Resources