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
Related
I created a "user" named model with base class "User". I'm trying to login a user in Angular App using lb-ng generated service but it's not logging in.
In my Login controller I invoked User.login() providing email and password but its giving some weird error.
Even I included this code in my app.js
// Use a custom auth header instead of the default 'Authorization'
LoopBackResourceProvider.setAuthHeader('X-Access-Token');
// Change the URL where to access the LoopBack REST API server
LoopBackResourceProvider.setUrlBase('http://.../api');
In loginController
console.log(User.login({ email: "shah.khokhar#hotmail.com", password: "12345" }));
But it's giving this validation error:
Kindly help me on this.
Thanks,
If you could post your user.json file and your actual angular code then it would be more clear. But as far as I can see, there are things you are doing wrong.
You are making a request to User model instead of your custom user model which obviously won't work as your user data is present in your custom model and not the built in User model
You are most probably making a POST request to a wrong method than login method as login method request url looks something like this
http://localhost:3000/api/users/login
Here's a working sample code for login function which I use for my project
self.login = function () {
var data = {
email: self.email,
password: self.password
};
users.login(data).$promise
.then(function (user) {
$state.go('home');
})
.catch(function (err) {
$state.go('auth.register');
});
};
Hope this helps.
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 currently have an issue with one of my apps.
The issue is that a user can keep the page open for a prolonged period of time before entering any data, so occasionally, when they enter data and hit the submit button, they are redirected to o365 for authentication and therefore lose the entered data.
I have all the standard authentication working for the app. However, i believe in order to do this, i would need to get a refreshed token in javascript when the submit button is clicked, and send this token to an api method in order to give access.
Is this possible and does anybody know how to go about it?
It is an MVC ASP.NET application using Owin O365 security with Microsoft Azure AD.
I am not sure what information or code snippets would be relevant here so if there is anything i can provide, please ask.
I have found multiple examples of getting tokens etc with angular, however, this is not an SPA and does not use angular.
Many Thanks in advance.
UPDATE
I have attempted to retrieve a token using ADAL JS using the following code but it doesnt seem to recognise the AuthorizationContext(config) call:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
$('#btnSubmit').on('click', function (e) {
e.preventDefault();
CheckUserAuthorised();
});
function CheckUserAuthorised() {
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: '##################',
clientId: '###################',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage'
};
var authContext = new AuthorizationContext(config); //THIS LINE FAILS
var user = authContext.getCachedUser();
if (!user) {
alert("User Not Authorised");
authContext.login();
}
else {
alert('User Authorized');
}
}
This gives the following error in console:
'AuthorizationContext' is undefined
UPDATE
I have no got passed the undefined error. This was because i was calling AuthorizationContext rather than AuthenticationContext. Schoolboy error. However now, whenever i check the user property of the context, it is always null. And i do not know a way around this as the context is initialised on page load.
There is a lack of a step in your code, here is a simple code sample, hope it will help you:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.10/js/adal.min.js"></script>
<body>
login
access token
get user
</body>
<script type="text/javascript">
var configOptions = {
tenant: "<tenant_id>", // Optional by default, it sends common
clientId: "<client_id>",
postLogoutRedirectUri: window.location.origin,
}
window.authContext = new AuthenticationContext(configOptions);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
function getToken(){
authContext.acquireToken("https://graph.microsoft.com",function(error, token){
console.log(error);
console.log(token);
})
}
function login(){
authContext.login();
}
function getUser(){
var user = authContext.getCachedUser();
console.log(user);
}
</script>
The code sample is from the answer of No 'Access-Control-Allow-Origin' header with Microsoft Online Auth. The issues are different but they are in the same scenario.
any further concern, please feel free to let me know.
I found a similar example on the web and your problem seems to be related to the object you are instantiating.
Instead of
new AuthorizationContext(window.config);
try
new AuthenticationContext(window.config);
The code ran just fine showing that the user was not authenticated.
I have the following functionality at my API and I strumbled upon a few questions:
POST /user (requires fullName, email, password) will create a new user, if the user has been created an unique activation ID is generated and a link to activate the account is send through mail to the user.
PUT /user (requires id, email) will activate the user.
Once the user has activated it's account, it can login.
POST /session (requires email, password) and logs in the user.
GET /session will look at the cookie session id and return user info if auth.
DELETE /session logs the user out.
Once the user is logged in, he is asked to submit their interests (just a HTML textarea) and they can submit a description about their account too (Location, gender, etc but it is all optional so also an HTML textarea just like Twitter account description)
Now my question is:
As you can see 2. PUT /user will activate the user, but how would I handle the submit interests and account description in a proper restful design?
Should I look at the point where at my backend server PUT /user will come in and detect the fields that where submitted?
Or would it make more sence to create a separated PUT /user/activate and PUT /user/interests.
Once this is finished, I want to expand it with restore password, also this would be a PUT /user wouldn't the field detection at the server side will get kinda messy?
Now about backbone, this is my session model:
var Session = Backbone.Model.extend({
url: '/session'
});
var session = new Session();
session.fetch(); // Get the user authentication of the backend server.
my user model:
var User = Backbone.Model.extend({
url: '/user'
});
function signup(fullName, email, password){
var user = new User();
user.save({
fullName: fullName,
email: email,
password: password
});
};
function activate(id, activationId){
var user = new User();
user.save({
id: id,
activationId: activationId
});
};
// Possibility...?
function submitInterests(id, interests){
var user = new User(url: '/user/interests/');
user.save({
id: id,
activationid: activationId
});
}
Thank you for reading.
A rule of thumb in RESTful world is:
Verbs down, nouns up.
That's because the magic 4 [GET, POST, PUT, DELETE] should be enough for all actions: no /users/activate / /user/edit stuff around.
While making a PUT over the whole /users for activation may seem legit, so would be making all the requests to /root and passing "entity = users, id = 3, ..." and so on.
I advice you to use /entityname for the collection [where you can POST to create a new one], then /entityname/:id in order to refer to a single entity [in this case, a single user].
Now you can make a PUT on /users/123 to accomplish whatever you need.
Of course you can nest resources:
/users/:id/interests
This is the route for all interests of :id-th user - you can issue a GET over it to retrieve them all, or a POST to add an element to the list, a PUT to set all the list from scratch.
One last thought about your session resource: a true RESTful service should be *stateless, i.e. it should not rely on session. Authorization has to be made on every request, see HTTP Basic Auth, though you can come with a session sometimes.
To be consistent to your schema, you can define a /user/:id/sessions resource where you can POST in order to make a new login, so you can keep track of user accesses.
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.