balteo
balteo

Reputation: 24679

Using Spring Security in order to display different content for the same URL based upon whether or not the user is authenticated

I use Spring MVC, Spring Security and Apache Tiles and I have the following issue:

I want unauthenticated users to land on the home URL of my website (i.e. www.mywebsite.com/) where a login form will be diplayed to them so that they can authenticate from there.

Then, once a user is authenticated, I would like for completely different page content to be displayed to them on the home URL of the website (still www.mywebsite.com/) possibly using another template/jsp.

What I am seeking to achieve is basically to be able to display different content for the same URL based upon whether or not the user is authenticated - all this using Spring security and Spring MVC.

I have researched Spring Security but was not able to find a solution to the problem described above. Others have run into similar issues (see: Spring security - same page to deliver different content based on user role)

Can anyone please provide pointers or advice as to how to implement this?

Upvotes: 4

Views: 2836

Answers (5)

gxet4n
gxet4n

Reputation: 369

You should do something like this :

@RequestMapping("/")
public String generalHomePage() {
    ...
}

@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String secureHomePage() {
    ...
}

Upvotes: 1

Rob Lockwood-Blake
Rob Lockwood-Blake

Reputation: 5056

I can think of a couple of ways of achieving what you want.

Firstly you could make use of the Spring Security taglib to conditionally render content in your View template dependent upon whether or not the user is correct authenticated. More information on the Spring Security taglib is here. Crudely, this would leave your View template looking something like:

if(user is authenticated)
     render content for authenticated user
else
     render log-in form

That feels a little bit blunt however as your Controller would always be creating the model regardless of whether or not your user was correctly authenticated. You would also need this logic in your View templates whenever you wanted to show a log-in form.

A separate approach would be to create a HandlerInterceptor implementation that forwards all requests to the Controller responsible for rendering the log-in page, until the user has fully authenticated. You could use the preHandle() method of your HandlerInterceptor to do this:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyHandlerInterceptor implements HandlerInterceptor
{

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
    SecurityContext sc = SecurityContextHolder.getContext();
    boolean userAuthenticated = true;
    /* Some logic in here to determine if the user is correctly authenticated */

    if(!userAuthenticated)
    {
        request.getRequestDispatcher("/login").forward(request, response);
        return false;
    }

    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
{

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
{

}}

You can then configure Spring MVC to map your HandlerInterceptor implementation onto the URLs that you require this functionality for. This avoids you having to duplicate the logic across all Controllers and is easily testable.

Upvotes: 1

balteo
balteo

Reputation: 24679

I was given a nice and elegant solution by a member of the Spring forum. Here it is:

@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
    return "authenticatedHomePage";
}

@RequestMapping("/")
public String homePage() {
    return "homePage";
}

It is quite nice because it relies upon Spring Security. See here (blog post)

Upvotes: 2

Josef Prochazka
Josef Prochazka

Reputation: 1283

you can try to use

<security:authorize access=”isAnonymous()”>
not authenticated page
</security:authorize>
<security:authorize access=”isAuthenticated()”>
authenticated page
</security:authorize>

or you can return "redirect: page_for_not_auth" in your controller as view name to redirect response to another controller/method wich handles not autheticated requests.

Upvotes: 0

kpentchev
kpentchev

Reputation: 3090

One solution I can think of is to check in your MVC controller the user principal from the request and if authenticated/has role to return one ModelAndView, otherwise return another:

@Controller
public class MyController{

    public ModelAndView doSomething(HttpServletRequest request, HttpServletResponse response){
        if(request.getUserPrincipal() != null && request.isUserInRole("someRole"){
            return new ModelAndView("view1");
        } 
        else {
            return new ModelAndView("view2");
        }
    }

}

Upvotes: 3

Related Questions