With Marcus' help, I was able to get this to work. The issue is I'm using
JSF/Primefaces components which are Ajax-enabled by default. I could have
set them all to false but data table is ugly and one of the reasons why so
many developers like JSF are the ajax capabilities.
In order to redirect using Ajax components you have to change things up a
bit:
1). Create a new filter that extends from AccessControlFilter:
public class HTTPStatusCodeAuthenticationFilter extends AccessControlFilter
{
/**
* This method is copied from AuthenticationFilter
* <p>
* Determines whether the current subject is authenticated.
* <p/>
* The default implementation
* {@link #getSubject(javax.servlet.ServletRequest,
javax.servlet.ServletResponse)
* acquires} the currently executing Subject and then returns
* {@link org.apache.shiro.subject.Subject#isAuthenticated()
* subject.isAuthenticated()};
*
* @return true if the subject is authenticated; false if the subject is
* unauthenticated
*/
@Override
protected boolean isAccessAllowed(ServletRequest request,
ServletResponse response, Object mappedValue) {
Subject subject = getSubject(request, response);
boolean isAuthenticated = subject.isAuthenticated();
return isAuthenticated;
}
/**
* Takes responsibility for returning an appropriate response when
access
is
* not allowed.
*/
@Override
protected boolean onAccessDenied(ServletRequest request,
ServletResponse response) throws Exception {
accessDeniedResponse(request, response);
return false;
}
/**
* Provides a 401 Not Authorized HTTP status code to the client with a
* custom challenge scheme that the client understands and can respond
to.
*
* @param request
* @param response
* @throws Exception
*/
private void accessDeniedResponse(ServletRequest request,
ServletResponse response) throws Exception {
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.addHeader("WWW-Authentication", "ACME-AUTH");
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
You can change the "ACME-AUTH' to whatever works for you.
2. Then add an entry to the shiro.ini or if you use Spring like I do,
applicationContext.xml:
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
*<property name="loginUrl" value="/index.faces"/>*
<property name="unauthorizedUrl" value="/login.jsp"/>
<property name="filterChainDefinitions">
<value>
/index.faces = anon
/** = *ajaxFilter*
</value>
</property>
</bean>
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="opacsRealm" />
</bean>
*<bean id="ajaxFilter"
class="org.pds.opacs.listeners.HTTPStatusCodeAuthenticationFilter"/>*
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean id="sha512Matcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA-256" />
<property name="hashIterations" value="1024" />
</bean>
<bean id="opacsRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="dataSource" />
<property name="authenticationQuery"
value="select PASSWORD, SALT from SEC_USERS where NAME
= ?" />
<property name="userRolesQuery"
value="SELECT ROLE_NAME FROM SEC_USERS_ROLES WHERE
USER_NAME = ?" />
<property name="permissionsQuery"
value="SELECT permission FROM SEC_ROLES_PERMISSIONS
WHERE ROLE_NAME = ?"
/>
<property name="permissionsLookupEnabled" value="true" />
<property name="saltStyle" value="COLUMN" />
<property name="credentialsMatcher" ref="sha512Matcher"/>
</bean>
3. Then, in your client page:
<pe:ajaxStatus onerror="window.location.replace('index.faces');"/>
index.faces is wherever you want the login page
This takes care of everything except for a page refresh (F5) after session
timeout. I never could get that to work because the page results in a 401
Error Page. I tried various jQuery code snippets but never could get them
to fire off. The closest I got was using *onunload=* which does allow me to
redirect to the login page on a page refresh. Unfortunately, the jQuery
code never fires off and I need to catch it so only after a session timeout
the page is redirected to the login page. Here's a few jquery snippets I
tried to get to work, so maybe somebody has a better way of catching a
session timeout on a page refresh:
1.
jQuery(document).ready(function() {
var request = jQuery.ajax({
url: "viewJobActivity.faces",
type: "POST"
});
request.done(function(msg) {
alert('done');
});
request.fail(function(jqXHR, textStatus) {
alert( "Request failed: " + textStatus );
});
});
2.
jQuery.ajax(
{
// Define AJAX properties.
method: "get",
url: "viewJobActivity.faces",
// Define the succss method.
success: function(){
alert( "Success!" );
},
// Define the error method.
error: function( objAJAXRequest,
strError ){
alert("Error! Type: " +
strError);
}
}
);
3.
var url = "viewJobActivity.faces";
jQuery.ajax({
url: "viewJobActivity.faces",
complete: function(xhr, statusText){
alert(xhr.status);
}
});
--
View this message in context:
http://shiro-user.582556.n2.nabble.com/Session-Timeout-doesn-t-redirect-to-login-page-tp7577730p7577750.html
Sent from the Shiro User mailing list archive at Nabble.com.