Ember Client Side Authentication, route authentication - javascript

I have been googling about this a lot but haven't been able to find satisfactory answer or solution you can say.
I have this Ember app, http://jsbin.com/aHiVIwU/28#.
My use case is pretty simple. I want to show the user whole app only after user gets authenticated. I am not using Ember Data as you can see, so the authentication will be through $.ajax as well.
If I am not wrong, I would have a template for login page like this,
<script type="text/x-handlebars" id="login">
<h1>Login</h1>
{{view Ember.TextField valueBinding="username"}}
{{view Ember.TextField type="password" valueBinding="password"}}
<button {{action 'login' class="btn"}}>Login</button>
</script>
Then I would map the resource,
App.Router.map(function() {
this.resource( 'login');
});
And then there would be a corresponding controller right?
App.LoginController = Ember.ObjectController.extend({
});
But the point where I am getting stuck is, how will I show only the login template first and then the whole app after the user gets authenticated? I would appreciate some explanation & help on this.

I can't say it any better than how Alex talked about it in his pull request with router facelift in ember. Look about a quarter of the way down, for 'How do I redirect to a login form for an authenticated route and retry the original transition later?':
https://gist.github.com/machty/5647589
Essentially at the root route of the resource where a user needs to be authenticated you will save the current transition, transition to the login route, then after they've authenticated, restart the previous transition.
He included a very simplistic example, where he's created a mixin that could be attached to all the routes requiring authentication and you wouldn't have to duplicate code etc.
http://jsbin.com/axarop/54/edit
App.NeedsAuthMixin = Ember.Mixin.create({
beforeModel: function(transition) {
// We're using beforeModel here to
// make sure the user is authenticated.
var loginController = this.controllerFor('login');
if (!loginController.get('hasLoggedIn')) {
alert('you must log in!');
loginController.set('afterLoginTransition', transition);
this.transitionTo('login');
}
}
});
App.ArticlesRoute = Ember.Route.extend(App.NeedsAuthMixin);
App.LoginRoute = Ember.Route.extend({
events: {
login: function () {
this.controller.set('hasLoggedIn', true);
var savedTransition = this.controller.get('afterLoginTransition');
if (savedTransition) {
this.controller.set('afterLoginTransition', null);
savedTransition.retry();
}
}
}
});

Take a look at the Client-side Authentication screen casts on http://www.embercasts.com/. They are from the same guy that made the examples that kingpin2k referenced, but provides a full, working solution.

Related

In Meteor, how/where do I write code that triggers when an authorized user has logged in?

New to Meteor, I'm using the alanning:roles package to handle roles.
I've managed to be able to only publish a collection when a user is logged in, when the page is first refreshed.
Meteor.publish('col', function(){
if (Roles.userIsInRole(this.userId, 'admin')) {
console.log('authed');
return Sessions.find({});
} else {
console.log('not auth');
// user unauthorized
this.stop();
return;
}
});
Logging out kills access to the collection (I'm using mongol to see). Logging back in after logging out, or logging in from a logged out state when the page is first loaded, will not give me access.
The webapp I'm trying to build is something like an ticketing system. I'm trying to be secure, so no unnecessary publishing if the user is not authorized.
What I'm trying to do is, get ticket information submitted from users from a collection, and display it on the client screen (as long as the client is authorized first). Maybe a better way to handle this is to force a refresh (how do I do that?) after a user change so unauthorized users are "kicked" out? And render all relevant data from the private collection right after the user is authorized?
I actually managed to get what I want for now with helpers...
In my ./client/Subs.js file:
Meteor.subscribe('col');
Template.NewTicket.helpers({ // match the template name
// move this into method later, not secure because on client??
isAdmin() {
console.log('is admin.');
console.log(Meteor.userId());
Meteor.subscribe('col');
return Roles.userIsInRole(Meteor.userId(), 'admin');
},
});
and then somewhere in my template file ./client/partials/NewTicket.html:
<template name="NewTicket">
{{#if isAdmin}}
{{/if}}
</template>
to trigger the check? I'm 99% sure theres a better way.

Sails.js create Index(root) Controller

I was wondering if there is a way to have an index controller with an index action. my root is a login page and I wanted to detect if the users session is already authenticated and if so redirect them to another page.
Is there specific notation for how the controller is named? I have already tried IndexController.js and MainController.js. I can't seem to find anything in the documentation about this.
Sails.js Ver: 0.11.0
You need to make the controller and action yourself. From there, set up a Policy to define access.
To make the controller, run sails generate controller Index in console.
Then, open api/controllers/IndexController.js, make it look something like this:
module.exports = {
index: function (req, res) {
// add code to display logged in view
}
};
Set up config/routes.js to look like this:
module.exports.routes = {
'get /': 'IndexController.index',
};
Afterwards, define a policy which has your authentication logic. Alternatively, you can use the included session authentication located at api/policies/sessionAuth.js assuming that your login action sets req.session.authenticated = true;. See the docs on policies for more info.
Lastly, connect the policy to the action in config/policies.js:
module.exports.policies = {
IndexController: {
'*': false, // set as default for IndexController actions
index: 'sessionAuth' // or the name of your custom policy
}
}

Calling the app config method inside ajax response - AngularJS

I am developing an app using angularjs and this is my first hands on using angular. Although, I have started understanding it and have developed some part of the app but I am stuck at one particular point.
I am trying to implement login functionality, so as the page loads, I am authenticating user and redirecting him to login page. On successful login, I am storing some values of user in one of the config provider.
Now I am using an API which has their own method of authentication and they have expose the ajax method which I can use to authenticate a user.
I have provided a snippet below. What I am primarily doing is using the external API, authenticating the user and once authenticated, I am getting roles associated to that user using another ajax method of the API, called "GetUserDetails".
And inside the response of the "GetUserDetails", I am injecting a provider and setting some values, so I can use this across my app.
The problem here is the app.config method is never called/executded. I mean the ajax request is returning response, and the alert is displayed on my page, but app.config is never executed.
But the same app.config if I call inside the done() of GetUser method, the app.config gets executed and stores values in my provider. But I want the GetuserDetails values also to be stored before I do anything in my app as I want to execute certain functionality based on user.
Below is my function in main.js file
function(angular,angularRoute,app,routes,configService){
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function() {
$.c.authentication.getUser()
.done(function(response){
if(response.userName!="anonymous"){
$.c.ajax({
method: "GetUserDetails",
parameters: {
User: response.user
}
})
.done(function(res) {
alert("I have reached the destination").
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(true);
configServiceProvider.setUserName(response.userName);
configServiceProvider.setUserObject(response);
configServiceProvider.setUserRoleDetails(res);
}]);
})
.fail(function(res) {
alert("Error while getting user roles ."+res);
});
angular.resumeBootstrap([app['name']]);
}
else
{
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(false);
configServiceProvider.setUserName(response.userName);
}]);
//Show Login Screen
var url = window.location.href.split("#")[0];
window.location.href = url + "#/Login";
angular.resumeBootstrap([app['name']]);
}
})
.fail(function(response){
$rootScope.isLoggedIn=false;
});
});
Here is my configServiceProvider
define(['../app'],function(app){
return app.provider('configService', function(){
var options={};
this.setLoginStatus = function(status){
//$rootScope.isLoggedIn = status;
options.isLoggedIn=status;
};
this.setPreLoginInfo=function(info){
options.preLoginInfo=info;
};
this.setUserName=function(name){
options.username=name;
}
this.setUserObject = function(userObject) {
options.userObject = userObject;
}
this.setUserRoleDetails = function(userRoleDetails) {
options.userRoleDetails = userRoleDetails;
}
this.$get=[function(){
if(!options){
}
return options;
}];
});
})
Can anyone please explain me what's going wrong here or what I am missing ?
Also, is there any alternative to achieve the same functionality ?
No luck in figuring out why the above scenario was not working. Since I had already spent lot of time behind this, I have found a workaround to achieve the same with the use of services.

Backbone router with no hashbangs

I've set up a super simple Backbone app with just a router and two views to try and nail down the correct way to handle routing with no hashbangs.
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'episodes': 'episodes'
},
index: function () {
var view = new IndexView();
view.render();
},
episodes: function () {
var view = new EpisodesView();
view.render();
}
});
var IndexView = Backbone.View.extend({
el: $('#primary'),
render: function () {
console.log('index view');
}
});
var EpisodesView = Backbone.View.extend({
el: $('#primary'),
render: function () {
console.log('episodes view');
}
});
var router = new Router;
Backbone.history.start({pushState: true});
I realize that the history object allows forward and backward navigation between pages, which is great. However, the way it's actually implemented seems a little messed up to me.
For instance, I created a simple MAMP server to serve an index.html file and the JS file. Navigating to http://backbone:8888/, the console logs index view like I'm telling it to. However, navigating to http://backbone:8888/episodes (by typing it into the address bar) returns a 404. BUT, if I navigate to http://backbone:8888/#episodes, the URL redirects to http://backbone:8888/episodes (without the hashbang) and I get episodes view logged to the console, which obviously means it's hitting that EpisodesView view.
From here, I can go back and forth between the index and episodes views. (back hits /, forward hits /episodes). That's all fine and dandy until I hit refresh while on /episodes again. 404...
So my question is this: how can Backbone be set up to handle URLs without relying on hashbangs? Everything I've found on the topic says "oh just pushState!". Well, I'm using pushState and, like I described above, you can't hit a URL like /episodes directly without getting a 404.
When you use push state, pages are served from the back end, which means that you have to define a corresponding route in your back end that corresponds to a front end route.
If the back end doesn't find the requested route, then it will deliver a 404 message, because it won't know what to serve. In your case, the episodes view gets triggered at the front end level, but the browser doesn't have a DOM to render the view when the page gets refreshed because nothing was served.
By default, the route http://backbone:8888/ will serve the index file because this is how the webserver is configured.
I'm not sure what back end technology you are using, but for serving a file from http://backbone:8888/episodes, just make sure that your back end has a router set up that serves the requested route and it should work.

Transition back to origin route

So. I have a very simple problem, that should have a simple solution. I'm just not seeing it.
In my ember app, I have a login route, and a link to this in the header. You click this, and get to a login form. When successfully logged in, I want to go back to the route displayed before the login form.
Something like the following url sequence
/post/209 - user clicks login
/login - user provides credentials, submits, and
/post/209 - is displayed
I haven't tried this out and this may not be the most elegant solution, but could you not simply do window.history.back() and the Router will take care of the rest?
To answer my own question, you can use the didTransition hook on Router, like this
App.Router.reopen({
didTransition: function(infos) {
this._super(infos);
var currentRoute = infos[infos.length - 1];
this.send('routeChanged', {
route: currentRoute.name,
context: currentRoute.context
});
}
});
infos contains an array of the active routes after transitioning. E.g. transition to PostEdit, the active routes will be
infos[0].name = 'application'
infos[1].name = 'post'
infos[2].name = 'post.edit'
In my application i catch the routeChanged event in ApplicationRoute, and keep a stack of the last ones in ApplicationController. The second entry in this stack is used to transition to the previous route.
Login page link should be a GET request with a link to the previous page.
like the following Ex, twitter
https://twitter.com/login?redirect_after_login=%2FitsWillyFerrell%2Ffollowers
Observe the redirect_after_login field is pointing to the username of the persons page I came from, so you have a place to go to once after login.

Categories