Reputation: 1080
My website allows unauthenticated (anonymous) users to perform a search of content which requires authentication to view. Currently, when they click on a link to view the details of one of the content items on the search results page Spring Security correctly identifies the user as unauthenticated and displays the login page. However, I would like to intervene and instead display a page to encourage the anonymous user to sign up for the website. I have traced what is happening in the filter chain but it's not clear to me whether I should extend an existing filter or handler or create a custom filter or handler. If it's the later I'm not sure where it should go.
When I run this through debug I can see the following happening:
ExceptionTranslationFilter.doFilter
executes FilterSecurityInterceptor
which determines that the detail page requires authentication (returns a -1 vote and throws an AccessDeniedException
)ExceptionTranslationFilter
catches the exception, determines the user is anonymous and calls the authenticationEntryPoint
, in this case LoginUrlAuthenticationEntryPoint
LoginUrlAuthenticationEntryPoint
invokes the DefaultRedirectStrategy
which redirects to the login pageSo, basically I need to override the redirection to the login page for this one use case. My best guess is to create a custom filter that checks for the combination of an anonymous user accessing this specific detail page and forces a redirect to the join up page, inserting the filter in the chain after ExceptionTranslationFilter
. Or is this total overkill for handling a single page redirect and there's an easier way to accomplish this?
Upvotes: 0
Views: 871
Reputation: 1080
For anyone interested, here's the code for the custom auth entry point, borrowing from LoginUrlAuthenticationEntryPoint
and ExceptionTranslationFilter
.
public class CustomAuthLoginEntryPoint extends LoginUrlAuthenticationEntryPoint {
private final Logger logger = LoggerFactory.getLogger(getClass());
private PortResolver portResolver = new PortResolverImpl();
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private RequestCache requestCache = new HttpSessionRequestCache();
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private String joinPageUrl;
public CustomAuthLoginEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
logger.debug("commence");
String redirectUrl = null;
if (!StringUtils.isBlank(joinPageUrl)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || trustResolver.isAnonymous(auth)) {
SavedRequest savedRequest = requestCache.getRequest(request, response);
redirectUrl = savedRequest.getRedirectUrl();
if (redirectUrl.indexOf("viewDetail") > 0) {
String joinPageUrl = buildRedirectUrlToJoinPage(request);
logger.debug("Redirecting to '" + joinPageUrl + "'");
redirectStrategy.sendRedirect(request, response, joinPageUrl);
return;
}
}
}
super.commence(request, response, authException);
}
protected String buildRedirectUrlToJoinPage(HttpServletRequest request) {
int serverPort = portResolver.getServerPort(request);
String scheme = request.getScheme();
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
urlBuilder.setScheme(scheme);
urlBuilder.setServerName(request.getServerName());
urlBuilder.setPort(serverPort);
urlBuilder.setContextPath(request.getContextPath());
urlBuilder.setPathInfo(joinPageUrl);
return urlBuilder.getUrl();
}
public void setJoinPage(String joinPageUrl) {
this.joinPageUrl = joinPageUrl;
}
}
I added this to my WebSecurityConfigurerAdapter
:
@Bean
public CustomAuthLoginEntryPoint customAuthLoginEntryPoint() {
CustomAuthLoginEntryPoint entryPoint = new CustomAuthLoginEntryPoint("/user/login");
entryPoint.setJoinPage("/user/join");
return entryPoint;
}
and the http configure:
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
.authenticationEntryPoint(customAuthLoginEntryPoint())
Upvotes: 1