Authentication with ajax in Play 2.1

I am writing a Play application where I will need authentication, which another web application will also handle. Therefore, when a user enters another web application, he must also enter the Play application.

To implement security on Play, I used the instructions in the documentation of the Play Framework: http://www.playframework.com/documentation/2.0.1/ScalaSecurity

My idea of ​​how to perform external authentication is for another application to make an ajax call to enter the Play application, as I thought it would write a session cookie for the user. But that does not work. I still have to log in manually when in the Play app.

Here is my controller:

val loginForm = Form( tuple( "username" -> nonEmptyText, "password" -> nonEmptyText) verifying("Invalid email or password!", result => result match { case (email, password) => Admin.authenticate(email, password) })) def jsLogin = Action { implicit request => { loginForm.bindFromRequest.fold( formWithErrors => BadRequest(toJson("Unauthorized!")), user => { Ok(toJson("Ok")).withHeaders( ACCESS_CONTROL_ALLOW_ORIGIN -> "*", ACCESS_CONTROL_ALLOW_METHODS -> "POST", ACCESS_CONTROL_MAX_AGE -> "300", ACCESS_CONTROL_EXPOSE_HEADERS -> "Origin, X-Requested-With, Content-Type, Accept" ).withSession("email" -> user._1) }) } } 

And here is the code I used for testing:

 $.ajax({ type: "POST", url: "http://localhost:9000/jsLogin", data: { username: "username", password: "password" } }) 

After debugging, I know that the jsLogin method works fine, and it logs in the user, and the response gets approval for the ajax method. But when I try to access my game application, it still asks me to enter the system manually.

Is there any inconvenient way to get the user to log in from the outside?

+4
source share
2 answers

Ok, I earned it. I noticed that the Set-Cookie header returned by the call was considered unsafe. To fix this, I had to correctly receive the CORS headers and send the credentials. So here is my new request (using XmlHttpRequest instead of jQuery ajax for debugging, should also work with ajax).

 var xmlhttp = new XMLHttpRequest(); var url = "http://localhost:9000/jsLogin"; var params = "username=username&password=password"; xmlhttp.open("POST", url, true); xmlhttp.withCredentials = true; xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlhttp.send(params); 

And here is the playback controller

 def jsLogin = Action { implicit request => { loginForm.bindFromRequest.fold( formWithErrors => BadRequest(toJson("Unauthorized!")), user => Ok(toJson("Ok")).withHeaders( ACCESS_CONTROL_ALLOW_ORIGIN -> "http://sending.host.url", ACCESS_CONTROL_ALLOW_METHODS -> "POST", ACCESS_CONTROL_ALLOW_CREDENTIALS -> "true", ACCESS_CONTROL_ALLOW_HEADERS -> "Origin, X-Requested-With, Content-Type, Accept").withSession("email" -> user._1) }) } } 

So the fix was that on the client side "withCredentials = true" and on the server side CORS headers were configured correctly.

+1
source

So, do you want to handle security using the Play session cookie? Have you verified that the cookie actually exists after an AJAX request? Is the "other" application in the same domain? If not, the cookie will not be used by another application.

By the way, the best way to handle this is described in a blog post by James Ward.

0
source

Source: https://habr.com/ru/post/1489197/


All Articles