要检索主题,我们可以使用 LoginModule 和 Valve 的组合。在身份验证开始之前调用阀门的事实在这里对我们有所帮助。当阀门被调用时,它将会话放入 ThreadLocal 中(类似于 JBOSS 如何将请求保存在 ThreadLocal 中),然后当 LoginModule.commit() 被调用时,它将主题保存到会话中。
要配置它,请将下面类的编译代码添加到 jar 中,并将其放在 $CATALINA_BASE/lib/ 下
package my.test;
import java.io.IOException;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.servlet.ServletException;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
/**
* Use following class to retrieve subject in your HTTPServlet when using Tomcat.
*/
public class ContainerServices extends ValveBase implements LoginModule {
// Key to revtieve subject from session.
public static final String SUBJECT_KEY =
"javax.security.auth.Subject.container";
/**
* Session for current thread.
*/
static InheritableThreadLocal<Session> sessionHolder =
new InheritableThreadLocal<Session>();
// JAAS Subject being authenticated.
private Subject subject;
// Invoke the value.
public void invoke(Request request, Response response) throws IOException,
ServletException {
sessionHolder.set(request.getSessionInternal(true));
try {
// Next in the invocation chain
getNext().invoke(request, response);
} finally {
sessionHolder.remove();
}
}
// Initialize the login module
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
}
// Store subject to session.
public boolean commit() throws LoginException {
Session session = sessionHolder.get();
if (session != null) {
session.getSession().setAttribute(ContainerServices.SUBJECT_KEY, subject);
}
return true;
}
// not used
public boolean abort() throws LoginException {
return false;
}
// not used
public boolean login() throws LoginException {
return true;
}
// not used
public boolean logout() throws LoginException {
return true;
}
}
在 $CATALINA_BASE/conf/server.xml 中添加以下 Valve 配置作为元素的子元素。
<Valve className="my.test.ContainerServices" />
在 jaas.config 文件中添加与 LoginModule 相同的类。
DummyAppLogin {
my.test.ContainerServices required debug=true;
my.test.DummyAppLoginModule required debug=true;
};
现在登录后,可以使用以下方式检索经过身份验证的主题。
session.getAttribute( ContainerServices.SUBJECT_KEY );