【问题标题】:Shiro in Java EE 6 applicationJava EE 6 应用程序中的 Shiro
【发布时间】:2013-08-21 23:27:41
【问题描述】:

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

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

问题是当我尝试对来自另一个容器的注入 EJB 执行此操作时(甚至是同一 EAR 中的一个 ejb jar)。

我得到的错误是:

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

用例是:

带有注入的无状态会话 bean B 的托管 bean AA 类驻留在 myApp.war 中,B 类驻留在 myApp.ejb 中,两者都在 myApp.ear 中。我正在从班级B 打电话给SecurityUtils

你有什么线索可以解决这个问题吗?

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

【问题讨论】:

    标签: jakarta-ee jsf-2 jboss7.x java-ee-6 shiro


    【解决方案1】:

    我自己回答问题。

    我使用过滤器和 JBoss 的自定义 LoginModule 解决了集成问题:

    过滤器(必须在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 {
        }
    }
    

    登录模块,它只是将用户设置为已验证:

    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>
    

    【讨论】:

    • 我面临同样的异常。你还记得具体是什么导致了这个问题以及这段代码是如何解决的吗?
    【解决方案2】:

    好吧,Shiro 通过ShiroFilterSecurityManager 绑定为ThreadLocal。查看doFilterInternal 方法。 Subject 绑定到ThreadContext 仅在内部 subject.execute 方法,这意味着SecurityUtils.getSubject() 每次在subject.execute 外部调用时都会返回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 集成。

    【讨论】:

    • 您好,感谢您的意见。我将 EJB3.1 与 JSF2 一起使用,目前无法切换到 Guice 或 Spring。实际上ejb是在shirofilter的同一个线程中调用的,我不知道为什么当谈到EJB3.1项目的堆栈时,Shiro ThreadLocal就消失了。也许我可以使用第二个过滤器手动添加它,但是可能是 EJB 堆栈的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-02
    • 2018-03-17
    • 2012-01-19
    • 1970-01-01
    相关资源
    最近更新 更多