Our last post covered the new Update feature of NixMash Spring Posts. Although the [Edit] link appears only on the Post Permalink page for the post author, without proper security access anyone could go directly to /posts/update/[postId] and update the post! Fortunately Spring Security Method Access Control Expressions make that easy to prevent.
Here's our Spring MVC Method's @PreAuthorize annotation for the post/update/ url. We're going to return a Boolean from PostService canUpdatePost() determining if the user can view the page. We pass the current authenticated user from Spring Context and the #postId Path Variable which is preceded by a hashtag. Having built-in expressions like current authenticated user is handy. See the Spring Security Docs for the complete list.
Now to our PostService canUpdatePost() method. We first handle the anonymous user who is not logged in, then with a valid Authentication object we create our custom CurrentUser Principal object and retrieve the post by its postId. To determine if the current user is the post's author, we return the results of the comparison of the post.getUserId() with the user's Id.
When anonymous users try to load the Update Post page they are redirected to the login page. Authenticated Users are forbidden to view the page so they are forwarded to the site's /403 page.
We configured Spring to route access denied to /403 in our SecurityConfig class.
Our MVC 403 handler.
This was something interesting when testing the Spring MVC Method @PreAuthorize expression. It is shown again below. I kept getting errors when using @postService, instead having to use the actual class name of @postServiceImpl. I knew something was wrong and that I should be able to use the Bean Name…
Apparently, to use the Bean Name in a Security Expression the name has to be explicitly set in the @Service Annotation. Interesting, eh?
Here are the integration tests which demonstrate the functionality we described in this post. The new Spring Security User Annotations really simplify security tests.
This is actually our second post on Spring Security Expressions. We used them on the User Profile page with url /[username]. Only the CurrentUser with that username could view /[username]. If you read that post, we used a method expression similar to the one used here because we wanted ADMIN users to be able to view the user's profile as well. We have since removed the requirement of ADMIN users viewing the profile so we were able to simplify the Security Expression shown below. Now that's sweet!