AngularJS/Spring MVC, HttpSession not persistent - angularjs

We are developing a web application, we're using Spring MVC (along with Spring Boot and Spring Security) and AngularJS.
Therefore, we have two distinct servers running for the application.
We are trying to store the user session backend, to ensure a proper level of security, so we tried to use the HttpSessionobject, but every time we want to retrieve the existing session, a new instance is created (we've checked the session ids).
Here's what we're doing to login :
$scope.authenticate = function () {
var postObject = new Object();
postObject.mail = $scope.userName;
postObject.password = $scope.userPassword;
$http({
url: "http://localhost:8080/login",
method: "POST",
dataType: "json",
data: postObject,
headers: {
"Content-Type": "application/json"
}
}).success(function successCallback(response, status) {
if (status == 200) {
$scope.messageAuth = "Login successful"
$scope.go('/services');
}
})
.error(function errorCallback(error, status) {
$scope.messageAuth = "Error " + response;
});
};
Then, we check the credentials, if they are correct, we store the user information into a new session :
#RestController
public class UserController {
#Resource
UserService userService;
#CrossOrigin
#RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<User> loginSubmit(#RequestBody User user, HttpServletRequest request, HttpSession session) {
if (isAuthorized(user)) {
User authenticatedUser = this.userService.getUserByMail(user.getMail());
authenticatedUser.setPassword(null);
session.invalidate();
HttpSession newSession = request.getSession(true);
newSession.setAttribute("USER_ROLE", authenticatedUser.getRole());
System.out.println("/login : SESSION ID = " + newSession.getId());
System.out.println("/login : " + newSession.getAttribute("USER_ROLE"));
return ResponseEntity.ok(authenticatedUser);
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(null);
}
}
#RequestMapping("/user")
public String user(Principal user, HttpServletRequest request, HttpSession session) {
System.out.println("/user : SESSION ID = " + session.getId());
System.out.println("/user : " + (String) request.getSession(false).getAttribute("USER_ROLE"));
return (String) session.getAttribute("USER_ROLE");
}
And finally, from the Angular app, we'd like to get the user information by calling /user like this :
var f = function() {
$http.get('http://localhost:8080/user').success(function successCallback(response) {
console.log(response);
}).error(function() {
console.log('error');
})
};
We've already tried pretty much every we found about how to manage a session with Spring Security, maybe the problem comes from the Angular part?
Any help would be greatly appreciated,
Thanks in advance

We found the solution, we just needed to add a few config lines in our app.js file :
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
More information here : link
Hopefully it will help someone, someday!

Related

angularJS post CORS

I am new to AngularJS and still learning. I have this angularJS code below to check my log-in credentials in my API. But upon log-in(clicking my log-in button) it does not hitting my break point in my API Code. Both API and Log-in codes are running from my local machine. I attached the picture for the CORS error.
AngularJS
data = {username:'user', password:'pass' }
app.service('services', function ($http, $window) {
services = {};
//Set the link once in upon open of project
localStorage.setItem('link', 'http://localhost:63763/');
var surl = localStorage.getItem('link');
services.signin = function (data) {
var result = $http({
method: 'POST',
url: surl + 'api/auth/signin', data: data,
}).then(function (response) {
return response;
}, function (err) {
return err;
});
return result;
};
return services;
});
API
[HttpPost]
[Route("signin")]
public IHttpActionResult Authenticate([FromBody] UsersSigninDTO dto)
{
//Codes
}
Class DTO
public class UsersSigninDTO
{
[Required(ErrorMessage = "username is required.")]
public string username { get; set; }
[Required(ErrorMessage = "password is required.")]
public string password { get; set; }
}
[Error Picture]
I solve it. On API Code side I added these code under the WebApiConfig.cs
config.MapHttpAttributeRoutes();
EnableCorsAttribute CorsAttribute = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(CorsAttribute);
You are using 2 different ports when calling localhost, thus triggering CORS.
App seems to be loaded from localhost:51216 and the requests to API by localhost:63763
What if you load your app from localhost:63763 ?
Maybe you are running 2 webpack instances at the same time? Check your config.

$http.post in angularjs not work to me and $http.get has response errors

I am new to angularjs am tying to learn it but some problems faced me, actually they are two problems:
First Problem: $http.post never works as there is no action and there is no response. However, $http.get is able to work.
Second Problem: Because of the first problem I call my restful webservice by $http.get, but the web service response status always is -1. Though the web service is able to do its work successfully and always response data null, can any one help me.
this my angular part:
var app = angular.module('myLogin',[]);
app.controller('loginController',function($scope,$http){
$scope.login=function(){
var username = $scope.username;
var password = $scope.pass;
$http.get("http://localhost:8080/spring/webservice/login/"+username+"/"+password)
.success(function(data,status){
alert("data : "+data);
alert("Data Inserted Successfully");
window.location.href = "chatScreen.html";
})
.error(function(data,status){
alert("Status: "+status);
window.location.href = "login.html";
});
}
});
and this my web service:
/**
* web service part
*/
#RequestMapping(value="webservice/login/{name}/{pass}", method=RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<String> weblogin(#PathVariable("name") String name, #PathVariable("pass") String pass)
{
System.out.print("username : "+name);
System.out.print(pass);
UserService service = new UserService();
List<UserBean> users = service.getUsers();
if(users!=null)
{
for(UserBean user : users)
if( ( user.getUsername().equals(name) ) && ( user.getPassword().equals(pass) ) )
{
System.out.print("success");
username = name;
//model.addAttribute("result", "Welcome to chat..");
MessageService messageService = new MessageService();
List<MessageBean> messages = messageService.getMessage(username);
String userMessages="";
if(messages != null)
{
for(MessageBean msg : messages)
userMessages +="\n"+msg.getSender() + ": " + msg.getMessage()+" \n";
}
else
userMessages +="You have no Messages !";
//model.addAttribute("whoSendToMe", userMessages);
return new ResponseEntity(HttpStatus.OK);
}
}
return new ResponseEntity<String>("faild", HttpStatus.NOT_FOUND);
}
refer this may be this will give you idea how to approach your problem:-
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this is asynchronous call back
// you will get your data here comming from rest
}, function errorCallback(response) {
// called asynchronously if an error occurs
});
share your code so we will try to solve it
If you use method GET and you receive a -1 returned, it means normally that you are giving a wrong URL.
As for then POST method you should use this syntax:
return $http({
method: 'POST',
url: 'index.php/email/createDeliverable',
data: $.param({
csrfTokenName: --your token--,
userName: user.name,
password: password
}),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
Remember to add the headers part.
Your server may need a CSRF token validation, in this case you need to pass it, see un my example: csrfTokenName: --your token--,

getting null using angular post

I'm having some problem using AngularJS post. I keep getting null from the server in my Angular success method even though server returns "success".
Here's my post req:
$http({
url: "/room/addUserInfo",
responseType:'json',
method: "POST",
data: json,
headers: {
"Content-Type": "application/json"
}
})
.success(function(data){
var a = data;
})
.error(function(data){
var a = data;
});
And this is my backend (Spring MVC):
#RequestMapping(value="/addUserInfo", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody String addEmployee (#RequestBody User user){
Database database = new Database(username, pass, dataName, port);
Connection connection = null;
try{
connection = database.connect();
database.addUserInfo(connection, user);
}catch(Exception e){
e.printStackTrace();
return e.toString();
}
return "success";
}
Just to mention, everything gets stored in the database, so the code is working and server returns "success" it's just that the success method on the client gets null every time. But, when I'm using Angular get method everything works.
Anyone had this kind of problem or knows how to fix this?
Thank you

angularjs $http service doesn't set cookie on POST but does with GET

The server side for my project provides WebApi 2.2
Client side is mobile application written in Ionic
Everything runs locally in chrome, mobile app in emulation mode.
1) On the server CORS is enabled and every API controller is decorated with:
[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
2) angular $http service is also configured to work with CORS:
$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
delete $httpProvider.defaults.headers.common['X-FirePHP-Version'];
3) After user authenticates itself, I'm sending back form API controller a cookie:
var cookie = new CookieHeaderValue("user-id", result.Entity.ToString());
cookie.Path = "/";
cookie.HttpOnly = true;
cookie.Secure = true;
response.Headers.AddCookies(new CookieHeaderValue[]{ cookie });
I can see this cookie in the response header:
Set-Cookie:user-id=306d5247-1d3b-4120-b412-6ce45105397a; path=/; secure; httponly
4) In WebApi pipeline I registered global DelegatingHandler to read cookies sent with requests
The strange thing, for me, is that when I do make POST call (this request is preflighted), then in delegating handler cookies collection is empty. While changing the method AcceptVerb (both on the controller and in javascript service) to GET fixes my problem and my cookie is present.
My js service is:
var setData= function (model) {
var deferred = $q.defer();
var url = stringHelper.format(endpoints.setData, sessionId);
var config = {
url: url,
method: 'POST',
data: {
name: model.name,
email: model.email
}
};
$http(config).then(function (result) {
deferred.resolve(true);
}, function (error) {
$log.debug(error);
deferred.reject(error);
});
return deferred.promise;
}
Important notice: Making POST calls to the same endpoint from Postman works correctly.
Does anyone have a similar problem?
Thanks
I finally figured it out:
1) after comparison of working GET request with failing POST, I noticed that GET wasn't preflighted with OPTIONS, while POST was
2) in the CORS definig materials I read that OPTIONS are not sending any cookies
As a resolution I added checking request method in my DelegatingHandler - so it's passing OPTIONS methods down into pipeline without checking for autentifiaction cookie.
Hope that will help someone :)
Here's my WebApi DelegatingHandler:
public class UserCookieHandler : DelegatingHandler
{
static public string ServerSessionId = "server-session-id";
static public string UserSessionId = "user-session-id";
const string LoginUri = "api/secured/login/login";
async protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string sessionId = string.Empty;
if (request.Method != HttpMethod.Options && !request.RequestUri.PathAndQuery.Contains(LoginUri))
{
string cookie = request.GetCookie(ServerSessionId);
if (cookie == null)
{
return request.CreateErrorResponse(HttpStatusCode.Forbidden, "Please log in");
}
else
{
sessionId = cookie;
try
{
Guid guid = Guid.Parse(sessionId);
}
catch (FormatException)
{
request.CreateErrorResponse(HttpStatusCode.BadRequest, "Please log in again");
}
}
request.Properties[ServerSessionId] = sessionId;
}
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
return response;
}
}

Angular controller doesn't pass value to web api method with $http

This is my angularjs code:
var uname = resetPasswordRequestData.email
var request = $http({
method: "post",
url: workModule.config.Config.CommonUrl + "api/ResetPasswordRequest",
data: uname
});
web api code:
public class PerformPasswordResetController : ApiController
{
public int PerformResetPassword([FromBody]string uname)
{
CrmUser contact = null;
if (ModelState.IsValid)
{
try
{
contact = new PasswordResetProvider().GetUserByName(uname);
}
catch (Exception ex)
{
return 1;
}
}
}
My problem is when I make the call from Fiddler it works, but when I run the code it nicely rout to the web api method but in web api controller "uname" argument is null. when I pass some data from fiddler it pass that data to "uname" (in web api controller uname is not null)
can anyone help me?
I strongly suggest you use a Model class to receive the data on your server.
Something like this:
public class UserModel {
public string UserName { get; set; }
}
public class PerformPasswordResetController : ApiController
{
public int PerformResetPassword([FromBody]UserModel user)
{
...Do your stuff
}
}
And on your angular code:
var model = {
userName: resetPasswordRequestData.email
};
var request = $http({
method: "post",
url: workModule.config.Config.CommonUrl + "api/ResetPasswordRequest",
data: model
});
Also, if you don´t want (or can´t) change your server code, try this please:
var uname = resetPasswordRequestData.email
var request = $http({
method: "post",
url: workModule.config.Config.CommonUrl + "api/ResetPasswordRequest",
data: {
uname: uname
}
});

Resources