我遵循BalusC代码来管理Java 6 (http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html)中的用户身份验证,如果我停留在同一个web容器中,这将非常有效。
我正面临着一个也许任何人都能帮我的问题。当注入驻留在Web容器中的EJB时,该SecurityUtils.getSubject()可以从该EJB的任何方法中工作。
问题是,当我试图从另一个容器(甚至是同一个EAR中的EJB jar )注入的ejb上执行时。
我得到的错误是:
由: org.apache.shiro.UnavailableSecurityManagerException:引起,调用代码不能访问SecurityManager,要么绑定到org.apache.shiro.util.ThreadContext,要么作为vm静态单例访问。这是一个无效的应用程序配置。
用例是:
带有注入的无状态会话bean A的托管bean B。类A驻留在myApp.war中,类B驻留在myApp.ejb中,两者都位于myApp.ear中。我打电话给SecurityUtils是B班的。
你对如何解决这个问题有什么线索吗?
我正在运行JSF 2、Java 6、JBoss 7.1。
发布于 2013-08-25 18:46:47
我自己来回答这个问题。
我使用过滤器和自定义LoginModule解决了JBoss的集成问题:
筛选器(它必须在shiro过滤器调用之后应用):
public class ShiroJAASIntegrationFilter implements Filter{
static Logger logger = Logger.getLogger(ShiroJAASIntegrationFilter.class);
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)arg0;
Principal userPrincipal = httpServletRequest.getUserPrincipal();
HttpSession session = httpServletRequest.getSession(false);
if(userPrincipal!=null){
if(session!= null && session.getAttribute("shiroAuthenticated")==null){
String name = userPrincipal.getName();
try {
httpServletRequest.login(name,"");
session.setAttribute("shiroAuthenticated",true);
} catch (ServletException e) {
logger.debug("Unable to authenticate user" + e.getMessage());
}
}
}
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}loginmodule模块,它只是将用户设置为身份验证:
public class ShiroJAASLoginModule extends UsernamePasswordLoginModule {
/**
* Always return true.
*/
protected boolean validatePassword(String inputPassword,
String expectedPassword) {
return true;
}
protected Group[] getRoleSets() throws LoginException {
//TODO: if needed, add roles
Group[] roleSets = { new SimpleGroup("Roles") };
roleSets[0].addMember(new SimplePrincipal(getUsername()));
return roleSets;
}
@Override
protected String getUsersPassword() throws LoginException {
return null;
}
}必须在standalone.xml中定义模块:
<security-domain name="shiro" cache-type="default">
<authentication>
<login-module code="web.security.shiroJaasIntegration.ShiroJAASLoginModule" flag="required"/>
</authentication>
</security-domain>最后,在应用程序jBos-web.xml中定义安全域:
<jboss-web>
<security-domain>shiro</security-domain>
</jboss-web>发布于 2013-08-20 17:48:00
好吧,Shiro通过SecurityManager将ThreadLocal绑定到ShiroFilter。看看doFilterInternal方法。Subject绑定到ThreadContext 仅在 subject.execute方法中,这意味着每当在subject.execute之外调用SecurityUtils.getSubject()时,SecurityUtils.getSubject()将返回null,这意味着ShiroFilter外部,这意味着外部请求线程,这就是我认为的问题。
AbstractShiroFilter.java
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
throws ServletException, IOException {
...
final Subject subject = createSubject(request, response);
//noinspection unchecked
subject.execute(new Callable() {
public Object call() throws Exception {
updateSessionLastAccessTime(request, response);
executeChain(request, response, chain);
return null;
}
});
...
} 你说你inject Stateless B你的DI框架是什么?Shiro可以很容易地与Guice和Spring集成。
https://stackoverflow.com/questions/18326128
复制相似问题