I'm trying to make authentication work with securesocial plugin for Play! framework 2.2.
I'm implementing my own version of UserService.
When someone logs into my website for the first time using some identity (Facebook, Twitter or everything else) I want to redirect him to a Registration Page to collect more informations about him and to make him accept my Terms and Conditions.
How can I achieve this?
Thank you for your help.
A.M.
def index = SecuredAction { implicit request =>
// Check if user is logging in for the first-time... or other logic
if(true){//If logic for redirection meets
Redirect(routes.Application.step2)
}else{
println("Home")
Ok(views.html.index(request.user))
}
}
def step2 = SecuredAction { implicit request =>
//Gather Other data... point to another form, your choice
Ok(views.html.step2(request.user))
}
I presume your files look like these..
securesocial.conf
securesocial {
onLoginGoTo=/
routes.conf
GET / controllers.Application.index
GET /step2 controllers.AmazonController.step2 //Additional Route
Related
I'm pretty new to Scala, the Play Framework and Akka. In the project I currently work on, the user of the web application should be able to ask the server several things to do (like starting a particular computation) in an asynchronous way. If the server is done it should notify the user also async. I solve this demand by a WebSocket connection which is established when the user first connects with the Application and the WebSocket is handled by a UserActor, which is attached to the User Session:
def ws = WebSocket.tryAcceptWithActor[JsValue, JsValue] { implicit request =>
Future.successful(request.session.get(UID) match {
case None => Left(Forbidden)
case Some(uid) => Logger.info("WebSocket has accepted the request with uid " + uid)
Right(UserActor.props(uid))
})
}
Currently, the only thing the UserActor does is receiving messages from the WebSocket as JsValue. The UID of the session is generated when requesting index:
def index = Action { implicit request => {
val uid = request.session.get(UID).getOrElse {
counter += 1
counter.toString
}
Ok(views.html.index(uid)).withSession {
Logger.debug("create uid " + uid)
request.session + (UID -> uid)
}}
}
The UserActor should represent the actual user on the Server and thus include the logic of all actions that the user can perform on the Server. This works fine as long as I send all user interaction over the WebSocket.
Now what is the case with other user input, like form submission? The application includes a form whose data should not go over the WebSocket, but rather be submitted with a POST request (perhaps with AJAX) and bound in a controller to the Model like described in the documentation.
def saveContact = Action { implicit request =>
contactForm.bindFromRequest.fold(
formWithErrors => {
BadRequest(views.html.contact.form(formWithErrors))
},
contact => {
val contactId = Contact.save(contact)
Redirect(routes.Application.showContact(contactId)).flashing("success" -> "Contact saved!")
}
)
}
This example is taken from the Playframework documentation.
Now, how do I link the Form Submission handler with the UserActor? Say I want to tell the user actor that a form has been submitted. A trivial example would be that the UserActor sends one value of the form back over the WebSocket to the client as soon it is received. So basically the problem reduces to the issue that I want to send the UserActor Messages from any Controller.
I might come up with the idea to send all form data over the WebSocket, but I also want to realize the upload of large data in the future, which I want to tackle like described in this blog post. Then one scenario I could imagine is that the UserActor should be messaged for each chunk it receives.
I guess one problem is that the UserActor and the WebSocketActor are the same and I rather should split their logic, such that the UserActor is only associated with the Session, but I have no idea how to accomplish this. Maybe I need another actor, say a UserManager, which keeps track of present UserActors and enables access to UserActors?
Do you have any suggestions, recommendations or perhaps an example application which also deals with this case? Thank you very much in advance.
Best regards
Don't use the actor that you pass to tryAcceptWithActor as a representation of the User. It should represent a particular session with that user. Possibly, one of many concurrent sessions (multiple browsers, or tabs) a user could have open at a particular time.
Create a separate actor to represent the user and all of the actions it can perform. Now the session actors should forward their messages to the user actor. Traditional controller methods can also forward requests to the corresponding user actors.
Or more precisely...
I already have an error page route defined like so:
GET /error controllers.pages.ErrorController.page(msg: String, returnTo: String)
And a controller method like this:
object ErrorController extends Controller {
def page(msg: String, returnTo: String) = ReceiverRestricted { implicit req =>
val action = List(Button(F8, "Continue", Call("GET", returnTo)))
Results.Ok(views.html.base(Html("Oops"), List(Html(msg)), None, action))
}
}
If I programmatically call, say, ErrorController.page("You did something daft!", "/home") I get to a page that looks like I want, ie:
Oops
You did something daft!
F8 Continue
However the url is ugly:
http://localhost:9000/error?msg=You%20did%20something%20daft!&returnTo=/home
I want to change this so the msg= query parameter doesn't appear in the url. How can I accomplish this? I tried removing the query parameter and redirecting to the error page with the message passed in via the flash cookie - that worked but reloading the browser page loses the message. I can't use the session cookie because I already store other data in the session almost upto its limit.
You can use flash feature.
Here is a sample:
In your controller you can redirect the user to error page with:
Redirect("/error").flashing(
"reason" -> "The item has been created"
)
And in Error action:
def error = Action { implicit request =>
Ok {
val reason = flash.get("reason").getOrElse("General Error")
//DO your stuff with reason variable
}
}
Obviously you can have as many as flash variables you want.
Since Play is restful and stateless, I can't see an easy way to pass on an error message during a redirect without using Play's flash. Of course you could store the message in an temporary cookie in the browser. Another possibility could be to store it in your database (or whatever persistence technology you use), but this seems to be like cracking a nut with a sledgehammer.
I've user roles: user, manager, admin. I need to authenticate them in controllers (methods). For example only admin can delete (now it looks like this, need to change that only admin should have permission):
def deleteBook(id: Int) = DBAction {
findById(id) match {
case Some(entity) => {
books.filter(_.id === id).delete
Ok("")
}
case None => Ok("")
}
}
I've many controllers and methods. I need to authenticate before process request (for example deleting book). My routes file contains:
...
DELETE /books/:id #controllers.Book.deleteBook(id: Int)
...
Some routes are only accessible to admin and manager. Some are for all types of users.
I'm currently seeing deadbolt2scala authorization module for play.
Can you recommend best way to authenticate multirole users in playframework scala?
I've managed to do this by using StackableControllers provided by https://github.com/t2v/stackable-controller
Basically, I use a basic access control list provided by my application.conf. I start by checking if there is a user in my request. If there is one, I can check if he has sufficient access rights to perform the action.
Such a feature may be implemented using BodyParser composition too. I've never done that, though, so someone else's advice may be better for you.
I'm developing an application using Play framework in scala. I have to handle the below use case in my application.
For a particular request from the browser to the play server the Play server should make an http request to some external server (for Eg: somesite.com) and send the response from this request back to the web browser.
I have written the below code to send the request to external serever in the controller.
val holder = WS.url("http://somesite.com")
val futureResponse = holder.get
Now how do I send back the response recieved from "somesite.com" back to the browser?
There's an example in the Play documentation for WS, under Using in a controller; I've adapted it to your scenario:
def showSomeSiteContent = Action.async {
WS.url("http://somesite.com").get().map { response =>
Ok(response.body)
}
}
The key thing to note is the idiomatic use of map() on the Future that you get back from the get call - code inside this map block will be executed once the Future has completed successfully.
The Action.async "wrapper" tells the Play framework that you'll be returning a Future[Response] and that you want it to do the necessary waiting for things to happen, as explained in the Handling Asynchronous Results documentation.
You may also be interested in dynamically returning the status and content type:
def showSomeSiteContent = Action.async {
WS.url("http://somesite.com").get().map { response =>
Status(response.status)(response.body).as(response.ahcResponse.getContentType)
}
}
Dynamic status could help if the URL/service you call fails to answer correctly.
Dynamic content type can be handy if your URL/service can return different content HTML/XML... depending on some dynamic parameter.
I have a web application in Play. The web application consists of several pages. In every page there is a small flag that enables the user to change the language (locale) from german to english and back.
I handle this with a redirect to referer:
def referer(implicit request: Request[AnyContent]) =
request.headers.get(REFERER).getOrElse(mainUrl)
def locale(l: String) = Authenticated { user =>
implicit request =>
Redirect(referer).withCookies(Cookie(LANG, if (l == "de" || l == "en") l else "de"))
}
It is working fine. Well, at least for GET requests.
I have a specific page where the user has to input data in a form. This form is then POSTed to the server. Were errors found, the form is displayed again with the error messages, as usual. Now, if the user wants to change the language (by clicking on the flag), the redirect to referer does not work, because it tries to use a GET request, and Play complains that a GET route does not exist for this method (which is true).
I am solving this by caching the form and defining another method where the form is taken from the cache:
# User data is POSTed to the server
POST /create/insert controllers.MyCreate.insert()
# After a redirect the cached form is displayed again
GET /create/insert controllers.MyCreate.insertGet()
It works, but I don't like this solution. It does not seem normal to have to create another entry in the routes and another method just to adress this problem. I would need to add this hack for every POST route in my application!
Is there a more elegant solution to this?
You could change it into something like this (untested):
def changeLang(lang:String, returnUri:String) = Action {
Redirect(returnUri)
.withCookies(Cookie(LANG, if (lang == "de" || lang == "en") lang else "de"))
}
In you template you would output the route to changeLang in the link, you can get the uri via the request
#routes.Application.changeLang("en", request.uri).url
I suggest you make request implicit in your action and define it as implicit in your template so you don't need to pass it on to each template.
// in the controller
def myUrl = Action { implicit request =>
Ok(views.html.myTemplate("something"))
}
// in the template
#(title:String)(implicit request:play.api.mvc.RequestHeader)
Edit
As for the POST requests, it common (for these types of framework) to have POST requests simple handle stuff and then redirect to another page. The usual flow is like this:
Form submits to a handler
Handler does something with the form information
Handler redirects to a page
An example:
// Hooked up to a GET route
def edit(id:Long) = Action {
// render the view with a form that displays the element with given id
// if the flash scope contains validation information, use that in display
}
// Hooked up to a POST route
def editHandler = Action {
// validate the form
// if validation succeeds
// persist the object
// redirect to edit
// else
// put the form information into the flash scope
// put any validation messages into the flash scope
// redirect to edit
}
If you do not want to use this flow you need to have both a GET and POST route anyway. The user might do a page reload on the resulting page.