Link Sails's authenticated user to websocket's user - angularjs

I am currently trying to create an sails+angular web-app.
I already have a user-authentication system working (based on this tutorial : https://github.com/balderdashy/activity-overlord-2-preview). I am trying to integrate a very simple chat inside using websocket.
My issue is to link websocket's "user" to the authenticated user.
Because when an authenticated user writes a message, I want to send the message as data but not the id of the current user, i would like to get this id from the sail's controller.
This is my actual sails chatController :
module.exports = {
addmsg:function (req,res) {
var data_from_client = req.params.all();
if(req.isSocket && req.method === 'GET'){
// will be used later
}
else if(req.isSocket && req.method === 'POST'){
var socketId = sails.sockets.getId(req);
/* Chat.create(data_from_client)
.exec(function(error,data_from_client){
console.log(data_from_client);
Chat.publishCreate({message : data_from_client.message , user:currentuser});
}); */
}
else if(req.isSocket){
console.log( 'User subscribed to ' + req.socket.id );
}
}
}
and this is my angular's controller
io.socket.get('http://localhost:1337/chat/addmsg');
$scope.sendMsg = function(){
io.socket.post('http://localhost:1337/chat/addmsg',{message: $scope.chatMessage});
};

req.session.me
...was the solution.

Related

Maintaining a Session in MVC .net application using angularjs

I am working on an application, in which a user if has an account in db can log in the website and then perform certain functions. One of those functions involve creating a blog. The blog is being displayed in another project application using the same database. Now when user creates a blog after logging in, i need to store who created the blog in order to do that, i came up with 2 ways. Either i keep passing the user id as a parameter on every page url or i can create a session in order to store it for the duration of login.
I think the latter is a better option but i am kind of lost on how to do it. I am creating a 3 project layer Application. with the client side done in angularjs. My c# controller is being used just to pass the json data to another layer, which then communicates with the database which is in another layer.
The project files are too big but i can write a example code for it.
Html:
<div ng-app="Module">
<div ng-controller="AppController">
<input ng-model="user.Email" type="email"\>
<button type="button" ng-click="UserLogin()"\>
</div>
</div>
AngualrJs:
var app = angular.module('Module', []);
app.controller("AppController", function ($scope) {
$scope.loginchk = function () {
Post("/User/LoginValidation", $scope.user, false, $("#btnlogin")).then(function (d) {
if (d.Success) {
window.location.href = "/User/LoggedIn?emailId=" + $scope.user.Email;
}
ShowMessage(d);
});
}
})
Controller:
public JsonResult LoginValidation(LoginUser user) {
return Json((new userLogic()).LoginChk(user), JsonRequestBehavior.AllowGet);
}
Business Logic LAYER----------------
UserLogic:
public Message LoginChk(LoginUser user) {
Message msg = new Message();
try {
Account userProfile = db.Accounts.Where(b => b.Email == user.Email).FirstOrDefault();
if (userProfile == null)
{
msg.Success = false;
msg.MessageDetail = "Account Email does not exist";
}
else
{
if (userProfile.password != user.Password)
{
msg.Success = false;
msg.MessageDetail = "Wrong Password";
}
else
{
msg.Success = true;
msg.MessageDetail = "Logged In";
}
}
}
catch(Exception ex)
{
msg.Success = false;
msg.MessageDetail = "DB connection failed.";
}
return msg;
}
Now I know i can create a Session Variable in the controller like this Session['Sessionname'] = user;
but i am not sure it will work with my application because i have multiple controllers and i will still have to pass it to them. so i dont see the point of maintaining a session variable in every controller even if its not used. How do i go about creating a session?
local storage is best option to do that :
window.localStorage.setItem("userId",useId);
to get again:
localStorage.getItem("userId");
You Can use client-side LocalStorage to save the user-id and use it where ever necessary,
as it will be saved in plain text you can encrypt and save it .
check here how to encrypt using javascript
https://stackoverflow.com/a/40478682/7262120

Angular + SignalR wait for promise

I have list of users for chat purpose, something like on facebook where i got all users from my database using ngResource. When user is offline i got red marker close to his name and when is online i use green marker.
What i want to archieve is that when user sign in, my red marker will turn into green. When user login into my app, my Hub method OnConnected() gets fired and call my client side code
Hub method when user sign in.
#region Connect
public override Task OnConnected()
{
var userDetails = new ApplicationUser
{
ConnectionId = Context.ConnectionId,
UserName = Context.Request.GetHttpContext().User.Identity.Name,
Id = HttpContext.Current.User.Identity.GetUserId(),
};
if (onlineUsers.Count(x => x.ConnectionId == userDetails.ConnectionId) == 0)
{
onlineUsers.Add(new ApplicationUser {
ConnectionId = Context.ConnectionId,
UserName = userDetails.UserName,
Id = userDetails.Id,
});
Clients.All.newOnlineUser(userDetails);
Clients.Caller.getOnlineUsers(onlineUsers);
}
return base.OnConnected();
}
#endregion
Client side code in my controller
$scope.online_users = UserService.getChatUsers();
PrivateChatService.addOnlineUser(function (user) {
angular.forEach($scope.online_users, function (value, key) {
if (user.UserId == value.Id) {
value.Active = true;
}
});
console.log("newOnlineUser finished");
});
Problem is with forEach method in my client side code. In that time when my signalR hub fires my method ".addOnlineUser" my $scope.online_users is not resolved so i only have promise but not data so i cant iterate through that array to change user status from offline to online. Is something how i can wait for promise to be resolved?
Update:
I had something like this but this is not definitely good aproach since i hit all the time my database to get users.`
PrivateChatService.addOnlineUser(function (user) {
var dataPromise = UserService.getChatUsers(function(response){
$scope.online_users = response;
angular.forEach(dataPromise, function (value, key) {
if (user.UserId == value.Id) {
value.Active = true;
}
});
});
console.log("newOnlineUser finished");
});

Firebase: How can i use onDisconnect during logout?

How can i detect when a user logs out of firebase (either facebook, google or password) and trigger the onDisconnect method in the firebase presence system. .unauth() is not working. I would like to show a users online and offline status when they login and out, minimize the app (idle) - not just when the power off their device and remove the app from active applications on the device.
I'm using firebase simple login for angularjs/ angularfire
Im using code based off of this tutorial on the firebase site.
https://www.firebase.com/blog/2013-06-17-howto-build-a-presence-system.html
Please i need help with this!
Presence code:
var connectedRef = new Firebase(fb_connections);
var presenceRef = new Firebase(fb_url + 'presence/');
var presenceUserRef = new Firebase(fb_url + 'presence/'+ userID + '/status');
var currentUserPresenceRef = new Firebase(fb_url + 'users/'+ userID + '/status');
connectedRef.on("value", function(isOnline) {
if (isOnline.val()) {
// If we lose our internet connection, we want ourselves removed from the list.
presenceUserRef.onDisconnect().remove();
currentUserPresenceRef.onDisconnect().set("<span class='balanced'>☆</span>");
// Set our initial online status.
presenceUserRef.set("<span class='balanced'>★</span>");
currentUserPresenceRef.set("<span class='balanced'>★</span>");
}
});
Logout function:
var ref = new Firebase(fb_url);
var usersRef = ref.child('users');
service.logout = function(loginData) {
ref.unauth();
//Firebase.goOffline(); //not working
loggedIn = false;
seedUser = {};
clearLoginFromStorage();
saveLoginToStorage();
auth.logout();
};
The onDisconnect() code that you provide, will run automatically on the Firebase servers when the connection to the client is lost. To force the client to disconnect, you can call Firebase.goOffline().
Note that calling unauth() will simply sign the user out from the Firebase connection. It does not disconnect, since there might be data that the user still has access to.
Update
This works for me:
var fb_url = 'https://yours.firebaseio.com/';
var ref = new Firebase(fb_url);
function connect() {
Firebase.goOnline();
ref.authAnonymously(function(error, authData) {
if (!error) {
ref.child(authData.uid).set(true);
ref.child(authData.uid).onDisconnect().remove();
}
});
setTimeout(disconnect, 5000);
}
function disconnect() {
ref.unauth();
Firebase.goOffline();
setTimeout(connect, 5000);
}
connect();

SocketIO syncUpdate model for different user

I have been writing an web app, where individual user will post their task and will be displayed on their news feed. I have used socket io with angular fullstack framework by yeoman.
what I am trying to do is, when user adds new data to goal model, on socketSyncUpadtes, $rootScope.getUserGoals get updated and user see new entry. but I want that to happen for each user, thats why I included userid, to make sure, it only pulls user specific data.
But in reality what is happening is, all connected user getting this socket stream and getting their model updated too, but as page refreshed it is always only what that query pulls, only user specific data.
this is how I get user specific data
$rootScope.getUserGoals = function (userid){
//get current todo task views
$http.get('/api/goals/name/'+userid).success(function(goals) {
$rootScope.userGoalArr = goals;
socket.syncUpdates('goal', $rootScope.userGoalArr);
});
};
then it displays in view with this
<ul class = "holdTaskul" ng-repeat="view in filtered = userGoalArr | orderBy:'-created'">
I looked up on google and search a lot to figure out how to separate each user socket stream and attached them to their login credential. I have come across this socket-jwt and session token. I am not expert on socket. I would much appreciate if someone could point me to right direction about this, what I am intending to do..
my socket configuration is as follows for socket.syncUpdate function
syncUpdates: function (modelName, array, cb) {
cb = cb || angular.noop;
/**
* Syncs item creation/updates on 'model:save'
*/
socket.on(modelName + ':save', function (item) {
var oldItem = _.find(array, {_id: item._id});
var index = array.indexOf(oldItem);
var event = 'created';
// replace oldItem if it exists
// otherwise just add item to the collection
if (oldItem) {
array.splice(index, 1, item);
event = 'updated';
} else {
array.push(item);
}
cb(event, item, array);
});
/**
* Syncs removed items on 'model:remove'
*/
socket.on(modelName + ':remove', function (item) {
var event = 'deleted';
_.remove(array, {_id: item._id});
cb(event, item, array);
});
},
I have also configured socket for sending auth token by this
// socket.io now auto-configures its connection when we ommit a connection url
var ioSocket = io('', {
// Send auth token on connection, you will need to DI the Auth service above
query: 'token=' + Auth.getToken(),
path: '/socket.io-client'
});
and used socketio-jwt to send the secret session to socket service by that
module.exports = function (socketio) {
socketio.use(require('socketio-jwt').authorize({
secret: config.secrets.session,
handshake: true
}));

google plus login api cookie

I am using google app engine python. I followed the example code to let user login. After this step am I supposed to create my own cookie or session to remember the user? Because when i refresh the page, the login button appears again.
This is the javascript.
<script src="https://apis.google.com/js/plusone.js" type="text/javascript"></script>
<script type="text/javascript">
/*
* Triggered when the accepts the the sign in, cancels, or closes the
* authorization dialog.
*/
function loginFinishedCallback(authResult) {
if (authResult) {
if (authResult['error'] == undefined){
gapi.auth.setToken(authResult); // Store the returned token.
toggleElement('signin-button'); // Hide the sign in upon successful sign in.
getEmail(); // Trigger request to get the email address.
} else {
console.log('An error occurred');
}
} else {
console.log('Empty authResult'); // Something went wrong
}
}
/*
* Initiates the request to the userinfo endpoint to get the user's email
* address. This function relies on the gapi.auth.setToken containing a valid
* OAuth access token.
*
* When the request completes, the getEmailCallback is triggered and passed
* the result of the request.
*/
function getEmail(){
// Load the oauth2 libraries to enable the userinfo methods.
gapi.client.load('oauth2', 'v2', function() {
var request = gapi.client.oauth2.userinfo.get();
request.execute(getEmailCallback);
});
}
function getEmailCallback(obj){
var el = document.getElementById('email');
var email = '';
if (obj['email']) {
email = 'Email: ' + obj['email'];
}
//console.log(obj); // Uncomment to inspect the full object.
el.innerHTML = email;
toggleElement('email');
}
function toggleElement(id) {
var el = document.getElementById(id);
if (el.getAttribute('class') == 'hide') {
el.setAttribute('class', 'show');
} else {
el.setAttribute('class', 'hide');
}
}
</script>
This is the login button.
<span id="signin-button" class="show">
<div class="g-signin" data-callback="loginFinishedCallback"
data-approvalprompt="force"
data-clientid="279937419542.apps.googleusercontent.com"
data-scope="https://www.googleapis.com/auth/plus.login
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile"
data-height="short"
data-cookiepolicy="single_host_origin"
>
</div>
</span>

Resources