2013-08-20 219 views
2

我跟随BalusC代码来管理Java EE 6(http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html)中的用户身份验证,如果我保持在同一个Web容器上,这非常有效。Shiro在Java EE 6应用程序

我正面临一个问题,也许任何人都可以帮助我。 注入驻留在Web容器中的EJB时,SecurityUtils.getSubject()可以从该EJB的任何方法运行正常。

问题是,当我尝试从另一个容器(甚至是在同一个EAR中的ejb jar)注入的EJB上执行它时。

我得到的错误是:

产生的原因:org.apache.shiro.UnavailableSecurityManagerException:没有调用代码SecurityManager的访问,无论是绑定到org.apache.shiro.util.ThreadContext或作为VM静态单例。这是一个无效的应用程序配置。

的使用情况是:

Managed Bean的A与注射无状态会话bean B。类A驻留在myApp.war中,类B驻留在myApp.ejb中,均位于myApp.ear中。我从B类呼叫SecurityUtils

关于如何解决这个问题,你有任何线索吗?

我正在运行JSF 2,Java EE 6,JBoss 7.1。

回答

1

我自己回答了这个问题。

我使用过滤器和JBoss的一个定义LoginModule解决了集成:

的过滤器(它必须四郎过滤器的调用之后被应用):

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 { 
    } 
} 

登录模块,它只是套作为认证的用户:

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> 

最后,在应用程序jboss-web中定义安全域。xml:

<jboss-web> 
    <security-domain>shiro</security-domain> 

</jboss-web> 
+0

我面临着同样的例外。你记得具体造成这个问题的具体原因以及这个代码如何解决这个问题吗? –

0

那么,Shiro绑定SecurityManagerThreadLocal通过ShiroFilter。看看doFilterInternal方法。所述Subject仅内部subject.execute方法,这意味着将SecurityUtils.getSubject()空它会被称为外subject.execute每个时间,这意味着外ShiroFilter,这意味着外请求线程返回结合ThreadContext,这是我想问题。

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集成。

+0

嗨,感谢您的输入。我使用带有JSF2的EJB3.1,目前无法切换到Guice或Spring。 其实ejb是在shirofilter的同一个线程中调用的,我不知道为什么当涉及到堆栈的EJB3.1项目时,Shiro ThreadLocal消失了..也许我可以使用第二个过滤器手动添加它,但也许这是EJB堆栈的问题。 –