How do I exclude certain Vaadin views from authentication? - java

I want to make a couple of Vaadin (v22) views accessible without a login, i.e. make them publicly available.
I looked at this tutorial, which is probably outdated: https://vaadin.com/learn/tutorials/securing-your-app-with-spring-security
There it says, that all views not using the #Secured annotation are publicly accessible. In my case it is different. Nothing is accessible at all, unless anotated with #PermitAll then logged in users can access the page.

As ever so often, I found the answer while preparing the question.
The annotation to use is #AnonymousAllowed
Example:
#Route(value = "/welcome", layout = PublicLayout.class)
#RouteAlias(value = "", layout = PublicLayout.class)
#AnonymousAllowed
public class PublicWelcomePage extends Div {
// create your view here
}
Official Vaadin v22 docs

Related

Spring MVC : Generating links which match the controller url pattern

I am writing a web app with Spring 4.0.
I have written my controllers in what I believe to be the normal way using the #RequestMapping annotation to define the url pattern which the controller handles.
The snippet below illustrates this for a controller which displays a testimonial ...
#Controller
#RequestMapping("/testimonialView")
public class TestimonialRequestController {
#RequestMapping(value="/{testimonialName}", method=RequestMethod.GET)
public ModelAndView testimonialRequest(#PathVariable String testimonialName, ModelAndView modelAndView) throws FileNotFoundException {
Testimonial testimonial;
. . .
}
}
Elsewhere in my application I want to generate a link bar which includes all the testimonials to include in my left hand nav.
At the moment, when I construct the href for the anchor element to go into the link bar, I am hardcoding the url, like this:
String href="/testimonialView/" + testimonialName;
This does not seem right. If later on I want to change the url structure I have to change it in at least two places - possibly more. Once where the incoming URL is matched to the controller, and once to construct the anchor element which a user will click to invoke that URL.
Is there a best practice way of dealing with this problem? It must be a common one. Is it as simple as using Constants to represent the URLs and accessing these from different places? I know my example is simple but I am assuming the problem must exist for much larger web apps with complex URL structure so I want to understand what best practice is.
I hope this isn't a stupid question. I am keen to ensure that I implement best practice right from the beginning. I have looked through Stackoverflow and Google but nothing quite answers this specific question.
Any help gratefully received.
The short answer is that you can't do this dynamically because #RequestMapping puts data into the code at compile time.
However, there are a couple of options that work.
You can define the string constants in a separate class - this will make it easier for you to change the names of URLs
You can explore the request mappings at runtime within Spring, so could have some code that found URLs you'd coded elsewhere - I've done this for identifying when a URL is dynamic content, vs coded content.
My recommendation is
public class URLs {
public static final String TESTIMONIAL_VIEW = "/testimonialView";
}
with
#RequestMapping(URLs.TESTIMONIAL_VIEW)
and
String href= URLs.TESTIMONIAL_VIEW + "/" + testimonialName;
There isn't any better practice for this afaik. Most you can do is, as Ashley said, is to use constants. But as with any other client-server situation such as the Web, if you change the contract (the url in this case) you'll have to do so for both the client (i.e. the links) and the server (the controller mappings).
I would also mention that your controller can be more general, for example have a "Testimonials" controller and "view/{name}" as an action within that controller.
Hope this helps

Tapestry 5 - decouple page class name from URL

Is there any baked-in way, or established Tapestry pattern, to decouple the name of a page Class from the URL which renders it?
My specific problem is that I have a page class in an English codebase but I want the URLs to be in another language.
For example, the Hello.java page should be accessible from www.example.com/hola rather than the standard www.example.com/hello - though it's fine if both of these URLs work.
Ideally I want something like an annotation to configure a different URL name in-place for each individual page class.
Off the top of my head I could solve this myself with a map of URLs to page class names and a custom RequestFilter to do the mapping on each request - but I don't want to reinvent the wheel if there's a baked-in way to do this or a better pattern that anyone can suggest?
Tynamo's tapestry-routing could help you. It depends on how do you want to generate the links to www.example.com/hola and www.example.com/hello
The #At annotation only allows one route per page, but you can contribute all the routes you want via your AppModule, like this:
#Primary
#Contribute(RouteProvider.class)
public static void addRoutes(OrderedConfiguration<Route> configuration, ComponentClassResolver componentClassResolver) {
String pageName = componentClassResolver.resolvePageClassNameToPageName(Home.class.getName());
String canonicalized = componentClassResolver.canonicalizePageName(pageName);
configuration.add("home1", new Route("/home1", canonicalized));
configuration.add("home2", new Route("/home2", canonicalized));
configuration.add("home3", new Route("/home3", canonicalized));
configuration.add("home4", new Route("/home4", canonicalized));
configuration.add("hola", new Route("/hola", canonicalized)); // the last one is going to be use by default to create links to the page
}
The routes are ordered and by default the last one is going to be used to generate the links.
Currently there is no way to avoid using the default route to generate the links.
Tapestry has a LinkTransformer but I've always found the API lacking since you don't have access to the default behaviour. Igor has written a blog post about the LinkTransformer API here
I've always found it necessary to decorate the ComponentEventLinkEncoder so that I can access the default behaviour and tweak it. See ModeComponentEventLinkEncoder.java and AppModule.java for an example which tweaks the default behaviour and does some string manipulation on the URL.
Thiago has created a url rewriter api here but I've never used it myself. I'm pretty sure his solution is based on decorating the ComponentEventLinkEncoder for outbound URLs and a RequestFilter for inbound URLs.

Using scala and java in play framework 2.1 : Session usage

I'm currently using the session() of play framework in my template :
#if(session().get("email")==null){
<li>Login</li>
}else{
<li>Logout</li>
}
This template is used in all of my views. Some of these views are controlled by a Java controller, and some are with a Scala controller.
When I click on links that lead to Java controllers, I have no problems, the links for login and logout are correctly handled.
When I click on links that lead to Scala controllers, I get a [RuntimeException: There is no HTTP Context available from here.]
From what I read in here about scala controllers, I understood that they didn't return the http context when rendering a page, but I really want to be able to use the session in my template.
I thought about using an argument session() in my view, templates and controllers, but I believe that there will be a conflict between the java session (play.mvc.http.session) and the scala session (play.api.mvc.session) when play will compile the html pages.
Am I stuck? Is there a possibility to force scala controllers to give back the http context ?
The root cause maybe the Java controllers and Scala controllers are handled differently.
I have my project in Java first, and then try to add more Scala controllers. I also came across this problem (BTW, I am using Play 2.3.2).
I tried to fix this by setting my own Http.Context in the TheadLocal variable using my own ActionBuilder.
import play.api.mvc._
import scala.concurrent.Future
import play.mvc.Http.Context
import play.core.j.JavaHelpers
object ContextAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
Context.current.set(JavaHelpers.createJavaContext(request))
block(request)
}
}
Then my Scala controller actions simply use this ContextAction instead:
class TestController extends Controller {
def test = ContextAction { implicit request =>
Ok(views.html.index())
}
}
And this way the index template can access all request() / session() / etc.
I may be wrong, but I think that your Scala controllers should look like:
def myaction() = Action { implicit request =>
...
}
instead of:
def myaction() = Action {
...
}
Ie, you have to add the request to the scope of your Action.
And add it also to your view, at the beginning of the file:
#(...)(implicit session:Session)
Okay I found a workaround this problem.
This is not really aesthetic, but it works, and gets rid of the problem entirely.
I created two different main templates : scalamain.scala.html and javamain.scala.html.
The scalamain template is used by all views that are controlled by a Scala controller, and used the usual trick to use the session (implicit arguments, see more here).
The javamain template is used by all view that are controlled by a Java controller. (these view use the session easily).
The two templates are of course, the same once rendered by play.
I end up with some redundancy in my code and it took to separate all the actions so that view are controlled by only one type of controller(scala or java).
I hope this will help others with the same problem. I validate this answer, as it solves the problem, but feel free to answer if you find a more gracious way to solve it.

How to make server-side domain models available to client-side web browser?

In my web application utilizing Spring MVC, I have a rich domain model.
I would like to make this domain model available to a client web browser. For example, as my domain model includes a class Person with methods Set<Person> getFriends() and DateTime getBirthday(), I would like to use these methods on the client side. Usage scenarios include
dynamically updating the visiting browser's HTML to list all friends when requested so by the user, or
sort persons in the HTML by their birthday.
Please notice I'm not looking here for accessing my domain model in the "view rendering stage" (e.g. JSP). I am looking here for accessing my domain model on my web application's users' browsers. So for example I don't want to sort Person instances during the "view rendering stage". I want this sorting to happen later, on my user's browser.
What are solutions to my challenge?
Javascript - there are frameworks that could help ease the burden. The scenario you have described is an Ajax call to some service. You could represent the data as json which would be lightweight and easy enough to add to the page using javascript.
Ember.js (specifically its Models) and Grails do exactly what you want when used together. I'm sure that you can use any Java framework to do this, but Grails makes it stupidly easy. Below are a few patterns to get you started, but here's a complete example app!
Domain class:
class Person {
String name
}
Controller:
class PersonsController {
def index() { render (["person": Person.list()] as JSON) }
}
Ember.js App:
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.RESTAdapter.create({
namespace: 'app'
})
)};
App.Person = DS.Model.extend({
name: DS.attr('string')
)};
In your browser, this single command will populate the in-browser data store by fetching /app/persons from the backend. Modifying the in-browser instances will automatically HTTP POST the updated instance to your Controller.
App.Person.list()
You'll want to check out my answer on getting the two to play together in perfect harmony for more complex applications.
Abdull have you looked at GWT(Google Web ToolKit) http://bit.ly/YYz2Yx?
Here is some sample code that illustrates creation of client side components.
e.g. loading contacts
VerticalPanel contactsPanel = new VerticalPanel();
contactsPanel.setSpacing(4);
String[] contactNames = constants.cwStackPanelContacts();
String[] contactEmails = constants.cwStackPanelContactsEmails();
for (int i = 0; i < contactNames.length; i++) {
final String contactName = contactNames[i];
final String contactEmail = contactEmails[i];
final Anchor contactLink = new Anchor(contactName);
contactsPanel.add(contactLink)
http://bit.ly/12MOhZQ (for actual code sample)
If you were not limited to the browser - and thus javascript, I'd scream RMI about now. Luckily, there seems to be a solution to make it work. I have not tried it, but it might be worthwhile:
jabsorb is a simple, lightweight JSON-RPC library for communicating
between Javascript running in the browser and Java running on the
server. It allows you to call Java methods on the server from
Javascript as if they were local, complete with automatic parameter
and result serialization.
https://code.google.com/p/jabsorb/
Two populer javascript MVC frameworks:
http://backbonejs.org/
http://knockoutjs.com/
You can try them personally. suggestion are always subjective, your choice are always subjective as well. so just feel it yourself.

Making a variable accessible in all Play 2.0 project views

It is sometimes desirable to share context variables with all views, such as the current user or navigational state. Looking through the documentation, I haven't been able to find a way to share such global context variables accessible to the template engine in all views.
Is this provided by the framework, or am I better off explicitly passing these variables to all views, perhaps by writing a wrapper method called in all controllers whose views need these global variables?
You can use for that Session and Flash scopes
public static Result index() {
// session is good for storing session data such as for an example logged user's info
session("username", "John Doe");
// flash is available only for next request (in this case for view rendering process)
flash("navId", "mainPage");
return ok(index.render("ellou' World"));
}
index.scala.html
#(message: String)
#main(message) {
#if(flash.get("navId")=="mainPage"){<h1>Great! You're on main page again</h1>}
<div>You're logged as #session.get("username")</div>
}
of course for data which are individual for each page (like sample navId) you can also pass it to the view, where you can declare required type other than String.

Categories

Resources