I'm creating an ST2 application where you can login/register etc.
I'm wondering what the normal way is of logging in and having the User state across the entire application.
I have a User model with a REST proxy to get/save the data. When you load up the application I'm doing this to grab the user:
launch: function () {
var User = Ext.ModelManager.getModel('App.model.User');
User.load("", {
success: function (user) {
// I have the user here but it's only within this scope
}
});
}
But doing this it's only available within this function... so what do people usually do to get ahold of the user across the whole application? just store it within the application like:
application.user = user;
or do you create a store with an ID of User, using the User model and then retrieve with:
launch: function () {
var User = Ext.StoreManager.get('User');
User.load(function(user) {
// Do application logged in stuff
self.getApplication().fireEvent('userLogsIn');
});
}
someRandomFunction: function () {
var user = Ext.StoreManager.get('User').getAt(0),
email = user.get('email');
console.log(email);
}
Thanks, Dominic
Generally speaking you cannot rely on any information you save locally in your JS application. It can be spoofed and altered relatively easy.
What you need to do is to send username/password combination to your server back end. Server then should return encrypted cookie which application will send back to the server with each following request. Only by decrypting and verifying this cookie server can be sure of identity of logged in user.
Related
Im looking for an authentication system where the user submits to an enpoint and a jwt is generated at this endpoint, im not sure how to implement this, my client side application does not make use of email address or stored information, it is in fact a dApp. I just need an endpoint that will calculate a value from a supplied seed phrase and a password if the processing of these values goes well ( and it nearly always will unless someone sends junk to the endpoint) then a jwt will be issued.. so far the out of box functionality with feathers cli means that i need to use local strategy and need an email address, I cant find any demos out there on this.. anyone got any pointers ? so far my auth is pretty default
const authentication = require('#feathersjs/authentication');
const jwt = require('#feathersjs/authentication-jwt');
const local = require('#feathersjs/authentication-local');
module.exports = function (app) {
const config = app.get('authentication');
// Set up authentication with the secret
app.configure(authentication(config));
app.configure(jwt());
app.configure(local());
// The `authentication` service is used to create a JWT.
// The before `create` hook registers strategies that can be used
// to create a new valid JWT (e.g. local or oauth2)
app.service('authentication').hooks({
before: {
create: [
authentication.hooks.authenticate(config.strategies)
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});
};
and heres my service:
// Initializes the `aerAuth` service on path `/userauthendpoint`
const createService = require('feathers-memory');
const hooks = require('./userauthendpoint.hooks');
module.exports = function (app) {
const paginate = app.get('paginate');
const options = {
name: 'userauthendpoint',
paginate
};
// Initialize our service with any options it requires
app.use('/userauthendpoint', createService(options) );
// Get our initialized service so that we can register hooks and filters
const service = app.service('userauthendpoint');
service.hooks(hooks);
};
I am relatively new to feathers but not to building auth systems (in PHP)
The Custom authentication strategy guide and the feathers-authentication-custom plugin probably allow to do what you are looking for.
It also depends on how you want to implement this. You can either use the custom strategy for every service (as in the case of the API key which has to be sent in the header with every request) or just before the /authentication service to allow creating a JWT (the issue here is that it needs to reference a userId or other entityId that exists in the database which you don't have).
The easiest way would be to go with the first options and a custom header (X-DAP-PASSWORD) which could look like this:
const custom = require('feathers-authentication-custom');
app.configure(authentication(settings));
app.configure(custom((req, done) => {
const password = req.headers['x-dap-password'];
if(checkPassword(req.app.get('seedPassphrase'), password)) {
// implement your own custom logic for loading and verifying the user
done(null, user);
} else {
done(new Error('Invalid passphrase'));
}
}));
I have a simple Backbone.js app with User model with different roles and I use json-server to emulate some backend basics. I need to make a basic authentication -- i.e. I need my User to be able to login and save his session somewhere (for that he wouldn't need to sign in each time he refreshes his browser). I've got a db.json file where I already have some users:
{
"users": [
{
"login": "admin",
"password": "password",
"role": "admin",
"id": 1
}
]
}
and here is my User model:
var User = Backbone.Model.extend({
defaults: {
login: "",
password: "",
role: ""
},
// Updated
url: function () {
return "http://localhost:3000/users?login=" +
this.attributes.login + "&password=" + this.attributes.password;
}
});
I don't get quite good how could I manage authentication (i.e. entering login and password in form and storing the user session without proper backend). I thought about making a token field in my User model and filling in in each time user signs in and saving it in cookies, but I don't get how could I do that either way. I would be very grateful if someone could help me with this task.
ADDDED This is my login function in my view:
signIn: function () {
var login = $('#js-login').val();
var password = $('#js-password').val();
if (login && password) {
var currentUser = new User({
login: login,
password: password
});
currentUser.fetch({
success: function () {
console.log(currentUser.toJSON());
},
error: function (err) {
console.log(err);
}
});
}
}
But instead of finding a user from my json-server it just creates a new user with all empty attributes except of values of #js-login and #js-password input fields
ADDED I guess I should find my users by the query in url above in my collection, but I don't actually get how I would manage that
Repo with my project
This is simplified flow for your app:
Each time user open your website, check his cookies.
If cookies contain user info (saved username, password), check match with the info in your DB. If matched, go to home page. Otherwise, clear cookies, go to login page
If cookies not contain user info, go to login page
In login page, after user success logged in, save user info to cookies for next time check.
You can use some mechanism to encode user info (tokens, encryption...) to secure info stored in cookies/sessions. But store authentication DB in client is really weak security point. Sample code below:
Model:
var User = Backbone.Model.extend({
url: function () {
return "users?login" + this.attributes.login + "&password=" + this.attributes.password;
},
isAdmin: function () {
return (this.get("role") == "admin");
}
});
In your view:
// Load username password from cookie (just simple example)
var username = $.cookie("username"),
password = $.cookie("password");
if (username && password) {
var userModel = new User({
login: username,
password: password
});
userModel.fetch({
success: function () {
if (userModel.isAdmin) {
// e.g. go to admin page
} else {
// e.g. go to normal user page
}
// Save to cookie/session here
},
error: function () {
// Go to login page
}
});
} else {
// Go to login page
}
About cookie, you can refer How do I set/unset cookie with jQuery?
About getting username/password input form, you can just use simple jquery selector (very easy to google for it, e.g. https://www.formget.com/jquery-login-form/)
Here you can refer to this plugin that uses mostly the jquery functions as mentioned in the documentation here
I would not be going into much detail as the documentaion is quite clear.
This refers to the authentication with the jquery
Now IF you want to authenticate the user using backbone.js
if the route came back with {loggedIn: false} the backbone router would send the user to the login/register pages only. But if it came back with a users profile information then it would obviously mean he had a session.
wire up $.ajax to respond to 401 (Unauthorized) status codes.
Also to mention as stated in this stackoverflow thread
Hope it may be able to help you a bit.
Here is the step by step guide to authenticate with backbone.js
I want to connect to a remote server and use that for logins. This was not particularly hard.
Remote = DDP.connect('http://somesite.com');
Accounts.connection = Remote;
Meteor.users = new Mongo.Collection('users', Remote);
However, when I call meteor methods on my local code (there are multiple servers, but one login), it does not recognize the user.
Meteor.methods({
'start': function () {
if (!this.userId) {
// ...
} else {
throw new Meteor.Error(401, 'Unauthorized');
}
}
});
This always results in an error, despite being logged in.
How can I set my local user to the same user as the remote user?
Let's rename the following:
Remote => Login Server
local => Default Server This is where you call the Methods
I think you are better served by logging into Default Server, which then relays the login attempt to the Login Server.
This way you will be logged in on Default Server (if Login Server confirms the credentials are valid) when you use the Meteor.Methods that are on Default Server.
Accounts.validateLoginAttempt allows you to run arbitrary code in a callback on a LoginAttempt, allowing you to pass the validation from Default Server to Login Server:
if (Meteor.isServer) {
Accounts.validateLoginAttempt(function(attempt) {
//psuedocode block
var res = LoginServer_Login(attempt.methodArguements)
if (res === true) return true; // Login Success
else return false; // Login Failed
});
}
I'm not sure of the best way to implement LoginServer_Login func, though I'd try using HTTP.post to communicate with Login Server first (and recommend using restivus on the Login Server, it will give you authentication routes out of the box).
I just came across this package: admithub:shared-auth
It requires a shared db between the two meteor apps though.
Beyond this, you probably need to look into full SSO solutions.
I'm currently writing a server-centric package for Meteor, and the relevant code looks something like this:
__meteor_bootstrap__.app.stack.unshift({
route: route_final,
handle: function (req,res, next) {
res.writeHead(200, {'Content-Type': 'text/json'});
res.end("Print current user here");
return;
}.future ()
});
This is obviously a relatively hacky way of doing things, but I need to create a RESTful API.
How can I access Meteor.userId() from here? The docs say it can only be accessed from inside a method or publish. Is there any way around that?
Things I've tried:
Capture it from a publish using Meteor.publish("user", function() { user = this.userId() });
Get the token + user id from the cookies and authenticate it myself using something like Meteor.users.findOne({_id:userId,"services.resume.loginTokens.token":logintoken});
Create a method called get_user_id and call it from inside my code below.
The thing that you need to target first is that to get something that can identify the user from headers (especially because you want to get the username at a point where no javascript can run).
Meteor stores session data for logins in localStorage, which can only be accessed via javascript. So it can't check who is logged in until the page has loaded and the headers have been passed.
To do this you need to also store the user data as a cookie as well as on localStorage:
client side js - using cookie setCookie and getCookie functions from w3schools.com
Deps.autorun(function() {
if(Accounts.loginServicesConfigured() && Meteor.userId()) {
setCookie("meteor_userid",Meteor.userId(),30);
setCookie("meteor_logintoken",localStorage.getItem("Meteor.loginToken"),30);
}
});
server side route
handle: function (req,res, next) {
//Parse cookies using get_cookies function from : http://stackoverflow.com/questions/3393854/get-and-set-a-single-cookie-with-node-js-http-server
var userId = get_cookies(req)['meteor_usserid'];
var loginToken = get_cookies(req)['meteor_logintoken'];
var user = Meteor.users.findOne({_id:userId, "services.resume.loginTokens.token":loginToken});
var loggedInUser = (user)?user.username : "Not logged in";
res.writeHead(200, {'Content-Type': 'text/json'});
res.end("Print current user here - " + loggedInUser)
return;
}.future ()
The cookie allows the server to check who is logged in before the page is rendered. It is set as soon as the user is logged in, reactively using Deps.autorun
My solution was inspired by the server part of #Akshat's method. Since I'm making a RESTful API, I just pass the userId/loginToken in every time (either as a param, cookie or header).
For anyone interested, I bundled it as a package: https://github.com/gkoberger/meteor-reststop
Firstly, should the static page that is served for the app be the login page?
Secondly, my server side code is fine (it won't give any data that the user shouldn't be able to see). But how do I make my app know that if the user is not logged in, to go back to a login form?
I use the session concept to control user login state.
I have a SessionModel and SessionCollection like this:
SessionModel = Backbone.Model.extend({
defaults: {
sessionId: "",
userName: "",
password: "",
userId: ""
},
isAuthorized: function(){
return Boolean(this.get("sessionId"));
}
});
On app start, I initialize a globally available variable, activeSession. At start this session is unauthorized and any views binding to this model instance can render accordingly. On login attempt, I first logout by invalidating the session.
logout = function(){
window.activeSession.id = "";
window.activeSession.clear();
}
This will trigger any views that listen to the activeSession and will put my mainView into login mode where it will put up a login prompt. I then get the userName and password from the user and set them on the activeSession like this:
login = function(userName, password){
window.activeSession.set(
{
userName: userName,
password: password
},{
silent:true
}
);
window.activeSession.save();
}
This will trigger an update to the server through backbone.sync. On the server, I have the session resource POST action setup so that it checks the userName and password. If valid, it fills out the user details on the session, sets a unique session id and removes the password and then sends back the result.
My backbone.sync is then setup to add the sessionId of window.activeSession to any outgoing request to the server. If the session Id is invalid on the server, it sends back an HTTP 401, which triggers a logout(), leading to the showing of the login prompt.
We're not quite done implementing this yet, so there may be errors in the logic, but basically, this is how we approach it. Also, the above code is not our actual code, as it contains a little more handling logic, but it's the gist of it.
I have a backend call that my client-side code that my static page (index.php) makes to check whether the current user is logged in. Let's say you have a backend call at api/auth/logged_in which returns HTTP status code 200 if the user is logged in or 400 otherwise (using cookie-based sessions):
appController.checkUser(function(isLoggedIn){
if(!isLoggedIn) {
window.location.hash = "login";
}
Backbone.history.start();
});
...
window.AppController = Backbone.Controller.extend({
checkUser: function(callback) {
var that = this;
$.ajax("api/auth/logged_in", {
type: "GET",
dataType: "json",
success: function() {
return callback(true);
},
error: function() {
return callback(false);
}
});
}
});
Here is a very good tutorial for it http://clintberry.com/2012/backbone-js-apps-authentication-tutorial/
I think you should not only control the html display but also control the display data. Because user can use firefox to change your javascript code.
For detail, you should give user a token after he log in and every time he or she visit your component in page such as data grid or tree or something like that, the page must fetch these data (maybe in json) from your webservice, and the webservice will check this token, if the token is incorrect or past due you shouldn't give user data instead you should give a error message. So that user can't crack your security even if he or she use firebug to change js code.
That might be help to you.
I think you should do this server sided only... There are many chances of getting it hacked unit and unless you have some sort of amazing api responding to it