I'm developing JSF application with Apache Shiro. I autenticate the user with Shiro and redirect her to home page there is no problem with that. After the authentication when I try to access login page, it doesn't redirect me the homepage. I can login again even when there is already loggedin user. I'm doing Programmatic Login as BalusC mentioned in his blog post.
[main]
credentialsMatcher = org.apache.shiro.authc.credential.PasswordMatcher
myRealm = com.example.security.myRealm
myRealm.credentialsMatcher = $credentialsMatcher
securityManager.realms = $myRealm
user = com.example.web.filter.FacesAjaxAwareUserFilter
user.loginUrl = /login.xhtml
[urls]
/login.xhtml = user
This filter is written from the blog post.
public class FacesAjaxAwareUserFilter extends UserFilter {
private static final String FACES_REDIRECT_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<partial-response><redirect url=\"%s\"></redirect></partial-response>";
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
HttpServletRequest req = (HttpServletRequest) request;
if ("partial/ajax".equals(req.getHeader("Faces-Request"))) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().printf(FACES_REDIRECT_XML, req.getContextPath() + getLoginUrl());
}
else {
super.redirectToLogin(request, response);
}
}
}
What is the problem and how can I redirect the user if she is already authenticated?
EDIT: For now I'm using PostConstruct annotation to redirect if the user is already authenticated. I'm open to any good solution.
Using the available dropdown, select the user for whom you wish to specify the redirect URLs. Then manually insert the after-login URL in the URL field. Then, if you want, you can add the after-logout URL in the Logout URL field. When you're done, click on the Add username rule button below.
WP Login and Logout RedirectUpon installation, you'll find the new Redirect Options menu in your sidebar. Click it, and you'll see two boxes: Login Redirect URL and Logout Redirect URL. Put the URL you want in and click Save Changes, and you're done.
The most common ways to implement redirection logic after login are: using HTTP Referer header. saving the original request in the session. appending original URL to the redirected login URL.
After the authentication when I try to access login page, it doesn't redirect me the homepage. I can login again even when there is already loggedin user
Neither Shiro nor the custom Shiro user filter are intented to prevent that. Shiro doesn't have builtin facilities for this. The custom Shiro user filter runs only when an unauthenticated user is found, not when an already authenticated user is found.
Preventing an authenticated user from accessing the login page directly is your own responsibility. Depending on business requirements you can do the following:
Just allow it. Perhaps the user just want to switch logins. You could if necessary conditionally show a message like:
<ui:fragment rendered="#{not empty request.remoteUser}">
You are already logged-in as #{request.remoteUser}.
By logging in as another user, you will be logged out.
</ui:fragment>
<h:form id="login">
...
</h:form>
Don't allow it, but stay in the same page. Conditionally hide the login form and show a message like:
<ui:fragment rendered="#{not empty request.remoteUser}">
Hey, how did you end up here?
You are already logged-in as #{request.remoteUser}!
</ui:fragment>
<h:form id="login" rendered="#{empty request.remoteUser}">
...
</h:form>
And, of course, make sure that your web application doesn't have anywhere a login link when the user is already logged in.
Don't allow it and redirect to the desired target page. This can in turn be done in several ways. Most clean approach is using a servlet filter.
@WebFilter(urlPatterns = "/login.xhtml")
public class LoginPageFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (request.getRemoteUser() != null) {
response.sendRedirect(request.getContextPath() + "/home.xhtml"); // Redirect to home page.
} else {
chain.doFilter(req, res); // User is not logged-in, so just continue request.
}
}
// Add/generate init() and destroy() with NOOP.
}
You can also do this in a preRenderView
event listener. A @PostConstruct
may be too late as the response may already be committed at that point. Note that redirecting without any form of feedback may be confusing for the enduser. In the filter, consider passing an additional parameter which should trigger a conditional message. Or in the preRenderView
event listener, set a flash scoped message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With