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
}
}
Related
I'm trying to create a custom route in Sails and according to their documentation, if I add the following in config/routes.js:
'post /api/signin': 'AuthController.index',
The request would be dealt with by the index action in the AuthController but that doesn't seems to work at all. When I try the /api/login in Postman, I get nothing back.
Please note that I've added restPrefix: '/api' in my config/blueprints.js. Please note I'm using Sails 0.12.x
What am I missing here?
Since you are pointing to a controller with method index on it, you need to add it to your controllers and send a JSON response from there, (since you are using post). here is a simple example
config/routes.js
'post /api/signin': 'AuthController.index',
api/controllers/AuthController.js
module.exports = {
index: function(req, res) {
var id = req.param('id');
if(!id) {
return res.json(400, { error: 'invalid company name or token'});
}
/* validate login..*/
res.json(200, {data: "success"};
}
}
Update
Since you already have the above its probably caused by the blueprints you have.
Blueprint shortcut routes
Shortcut routes are activated by default in new Sails apps, and can be
turned off by setting sails.config.blueprints.shortcuts to false
typically in /config/blueprints.js.
Sails creates shortcut routes for any controller/model pair with the
same identity. Note that the same action is executed for similar
RESTful/shortcut routes. For example, the POST /user and GET
/user/create routes that Sails creates when it loads
api/controllers/UserController.js and api/models/User.js will
respond by running the same code (even if you override the blueprint
action)
with that being said from sails blueprint documentation, maybe turning off shortcuts and remove the prefix you've added.
possibly the shortcuts are looking elsewhere other than your controllers thus returning 404.
the prefix is being added to your blueprint connected route, hence you need /api/api/signin to access it?
Note
I am unable to replicate your issue on my computer as its working fine over here. but i have all blueprint settings turned off.
module.exports.blueprints = {
actions: false,
rest: false,
shortcuts: false,
// prefix: '',
pluralize: false,
populate: false,
autoWatch: false,
};
I'm using ember-cli-simple-auth with ember-cli-simple-auth-token:
"ember-cli-simple-auth": "^0.8.0",
"ember-cli-simple-auth-token": "^0.7.3"
And i already made all configurations with my server to receive the token if the credentials matches with some user in my database.
My doubt now is how can i force redirect if a user tries to access one page if is not log in?
I'm using the following:
export default Ember.Route.extend(AuthenticatedRouteMixin, {});
And this is causing a blank page if the user is not authenticated.. but the redirect doesn't happen.. Am i missing some config here?
You need to change authenticationRoute:
// config/environment.js
ENV['ember-simple-auth'] = {
authenticationRoute: 'index' // or '/' or 'application'
};
I have a meanjs starter template (with yeoman generator).
Where can I add specific permissions to my modules? For instance,
'use strict';
// Configuring the Articles module
angular.module('adminpanel').run(['Menus',
function(Menus) {
// Set top bar menu items
//Menus.addMenuItem('topbar', 'admin panel', 'adminpanel/', 'adminpanel');
Menus.addMenuItem('topbar', 'Admin Panel', 'adminpanel', 'dropdown', '/buildings(/create)?');
Menus.addSubMenuItem('topbar', 'adminpanel', 'List Collections', 'adminpanel/collections');
}
]);
and the routes like so
'use strict';
//Setting up route
angular.module('adminpanel').config(['$stateProvider',
function($stateProvider) {
// Adminpanels state routing
$stateProvider.
state('listCollections', {
url: '/adminpanel/collections',
templateUrl: 'modules/adminpanels/views/list-collections.client.view.html'
}).
state('showCollection', {
url: '/adminpanel/collections/:collectionName',
templateUrl: 'modules/adminpanels/views/show-collection.client.view.html'
}).
state('showCollectionItem', {
url: '/adminpanel/collections/:collectionName/:itemId',
templateUrl: 'modules/adminpanels/views/show-item.client.view.html'
});
}
]);
Are these the correct places to add role-based authentication (on the client side), with added measure on the serverside (I've already done that)?
Does anybody know how I can add an option to the Menus.(some function), such as 'admin.hasPermission', without breaking it? Any resources on this sort of thing?
Thanks for the help!
I don't believe it is right practice to put your authentication, authorization code at the client side as well as server side. They should be on the server side only.
The point is, you have to replicate your authentication and authorization code in the client, anyone can read your mechanism to handle these situation and once a loophole is discovered, it would simply be followed by your server code as well.
I believe authentication and authorization logic should be restricted to server side only. If I am up against someone professional, it would at least make his task tougher.
In case you insist, you can create a wrapper around $http service, maintain a key value pair of what role can do what, and ensure all AJAX request go through your wrapper service where you can check whether it should be allowed. If yes, you can simply forward the request using $http and if not, throw an error.
Not sure about any previous version, but with version 0.4.0 there are parameter in the client config to control the visibility:
If you set isPublic: false and add a roles array you can set the user that can see the menu entry:
// Add the dropdown listCollentcions item
Menus.addSubMenuItem('topbar', 'adminpanel', {
title: 'listCollections',
isPublic: false,
roles:['admin'],
state: 'adminpanel.listCollections'
});
The implementation is in the core module (menu.client.services.js):
// A private function for rendering decision
var shouldRender = function(user) {
if (user) {
if (!!~this.roles.indexOf('*')) {
return true;
} else {
for (var userRoleIndex in user.roles) {
for (var roleIndex in this.roles) {
if (this.roles[roleIndex] === user.roles[userRoleIndex]) {
return true;
}
}
}
}
} else {
return this.isPublic;
}
return false;
};
Maybe you can give version 0.4.0 a try or have a look at the code and try to implement it urself.
I have an isAuthorized policy that returns true if the User is authorized to perform a given action against a given model and model instance.
Is there a way to apply this policy to the blueprint routes such that, for example, a GET request to file only returns the Files the current user is allowed to do a findOne on?
Similarly, could this same policy be applied to the blueprint populate results, such that only some of a User's associated Files would be returned in the populated array?
To do this currently I am overriding the find action in each controller which is less than ideal. If it could be applied using a policy without breaking blueprint routes/actions that would be awesome.
In my sails-permissions module, I override the sails.js response type so that controller only responds with models that the user is allowed to access.
See:
override response: https://github.com/tjwebb/sails-permissions/blob/master/api/policies/PermissionPolicy.js#L58
filter results: https://github.com/tjwebb/sails-permissions/blob/master/api/policies/PermissionPolicy.js#L86-L90
This is part of sails, maybe a new feature?
http://sailsjs.com/documentation/concepts/policies#?using-policies-with-blueprint-actions
{
UserController: {
find: ['isAuthorized', 'filterByUserId'],
findOne: ['isAuthorized', 'filterByUserId']
}
}
api/policies/filterByUserId.js
module.exports = function filterByUserId(req, res, next) {
if ( req.session.user ){
// Use existing req.options.where, or initialize it to an empty object
req.options.where = req.options.where || {};
// Set the default `userId`
req.options.where.id = req.session.user.id;
}
//safe to do if isAuthorized policy is enforced in tandem.
return next();
}
So in my angular js app in service called 'authService' I have the following resources:
var userAreaLogin = $resource('/api/user_area/login');
var userAreaSignup = $resource('/api/user_area/signup');
var session = $resource('/api/user_area/getSession');
var userAreaLogout = $resource('/api/user_area/logout');
but this doesn't feel quite right, I'm using only the get methods, for example:
this.login = function(credentials) {
var user = userAreaLogin.get(credentials, function() {
...
});
};
this.signup = function(userInfo) {
var signup = userAreaSignup.get(userInfo, function() {
...
});
};
I'm confused about what resources to use, should I have something like this?
var session = $resource('/api/user/session');
var userArea = $resource('/api/user');
userArea.get(credentials); //should login the user?
userArea.post(credentials); //should signup the user?
session.delete(); //should logout the user?
session.get(); //should get the sessions of the logged user if any?
By REST sessions are maintained by the client and not by the service. You should use HTTPS and send the username and password with every request (for example with HTTP basic auth headers) instead of using session cookies... (stateless constraint)
Ofc. on the client side you can have login and logout which will change the content of the auth headers sent via AJAX.
You are going to the right direction.
In a well designed REST API you should have something like this.
POST /users/sign_in # Create a user session (signs in)
DELETE /users/sign_out # Delete a user session (signs out)
POST /users # Create a new user resource
GET /users/:id # Get the user resource
Based on these API you can then define your services. I also suggest to use $http which is cleaner, although you'll write few lines of code more.
# Session related methods
Session.create
Session.delete
# User related methods
User.create
User.get
Hope this makes things clearer.