如何将 JNDI 与 WAX (Websphere Application Server 8.5.5) 一起使用

How to use JNDI with WAS (Web Spehere Application Server 8.5.5)

之前我没有真正使用过 Web Sphere Application Server (8.5.5),也没有任何 JNDI 的实际经验,我什至只使用过几天 Shiro。 我仍然需要为 JNDI 获取自定义 Shiro 领域,以便应用程序和 Shiro 共享领域的公共实例(并且领域可以通过注入访问 ejb-resources)

到目前为止我是这样做的:

WEB-INF/shiro.ini

[main]
realmFactory = org.apache.shiro.realm.jndi.JndiRealmFactory
realmFactory.jndiNames = realms/ShiroRealm
...

自定义 Shiro-Realm(暂时只是模拟)

import javax.faces.bean.SessionScoped;
@SessionScoped
public class MockRealm extends AuthorizingRealm implements Serializable {

  @Inject public UserMB user;

  @Override protected AuthenticationInfo doGetAuthenticationInfo(...) ...
  @Override protected AuthorizationInfo doGetAuthorizationInfo(...) ...
}

自定义 CredentialsMatcher

public class MockCredentialsMatcher implements CredentialsMatcher {

  @Override public boolean doCredentialsMatch(...) ...
}

我有一个 shiro-startup class 如下

@Singleton
@Startup
public class ShiroStartup {

  @Inject
  private MockRealm realm;

  @PostConstruct
  public void setup() {
    Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
    InitialContext ic = new InitialContext(env);

    try {
    Object obj = ic.lookup("realms/ShiroRealm"); // This is expected to fail when the application is published
        } catch (NamingException ne) {
            this.realm.setCredentialsMatcher(new MockCredentialsMatcher());
            ic.rebind("realms/ShiroRealm", this.realm);
            System.out.println("Bound: realms/ShiroRealm";
        }
    } catch (NamingException e) {
        e.printStackTrace();
    }
  }
}

我之前发现 post 建议以这种方式桥接注入范围,实际上这可行,但仅当此代码在 GlassFish (v4) 上 运行 时。 我很确定这也适用于 WAS 8.5.5,但无法解决此错误。 (也许对某些人来说微不足道,但是......)

我收到的错误是抱怨找不到/无法使用 jndi 名称 "realms/ShiroRealm"。 (稍后我会 post 确切的异常,目前 运行 宁服务器有问题) 我还没有找到应该如何给出这个名字(这开始需要时间,即使我希望这种信息很容易找到),所以我 post 在这里希望有人可以给我建议。

(注意:我只在此处复制了我认为相关的部分。在 GlassFish 上 运行 调试代码时,我在预期的所有正确位置都得到了命中)

// 更新(为了完整性,虽然我认为这些与这个问题无关)
beans.xml

的内容
<?xml version="1.0" encoding="UTF-8"?>
<beans
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd">
  <interceptors>
    <class>com.example.interceptor.ShiroSecuredInterceptor</class>
  </interceptors>
</beans>


ejb-jar.xml

的内容
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
  version="3.1">
<interceptors>
  <interceptor>
    <interceptor-class>com.example.interceptor.ShiroSecuredInterceptor</interceptor-class>
    </interceptor>
  </interceptors>
  <assembly-descriptor>
    <interceptor-binding>
      <ejb-name>*</ejb-name>
    <interceptor-class>com.example.interceptor.ShiroSecuredInterceptor</interceptor-class>
    </interceptor-binding>
  </assembly-descriptor>
</ejb-jar>

web.xml

的内容
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID"
  version="3.1">
<display-name>shiroTest</display-name>
<context-param>
  <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
  <param-value>true</param-value>
</context-param>
<welcome-file-list>
  <welcome-file>Login.xhtml</welcome-file>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  <listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
  </listener>
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
    </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
</web-app>

//更新
终于让服务器重新联机并且能够抛出异常

 [4/17/15 12:16:22:053 EEST] 00000043 SystemErr     R javax.naming.NameNotFoundException: Context: securityoffNode01Cell/nodes/securityoff/servers/server1, name: realms/ShiroRealm: First component in name realms/ShiroRealm not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]

如果完整的堆栈跟踪很重要,我把它放在 pastebin 上一段时间了。 http://pastebin.com/sANAqCJL

(意识到我用来在 GlassFish 上测试此配置的项目是一个简单的 'war'-project,其中部署在 WAS 上的实际实施正在酝酿之中。这些服务器之间可能相关也可能不相关。 )

// 更新 2 读完这篇文章后(还没有完全读完,仍在阅读和测试): http://www-01.ibm.com/support/knowledgecenter/SS7JFU_7.0.0/com.ibm.websphere.express.iseries.doc/info/iseriesexp/ae/cejb_bindingsejbfp.html

我尝试使用名称:"ejblocal:MockRealm"。 好吧,这似乎没问题。但是继续处理同样的问题,现在出现以下异常。

[4/17/15 13:17:47:536 EEST] 000000ac webapp        E com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor]: java.lang.IllegalStateException: Unable to look up realm with jndi name 'ejblocal:MockRealm'.

看起来 shiro.ini 中使用的 jndi 名称还需要修复其他问题,但是 'ejbLocal:MockRealm" 或 "simply "MockRealm" 不正确。 我希望尽快找到解决方案,然后我会 post 一个真正的答案。

您是否尝试删除您传递到此处的 "env" 参数?

//InitialContext ic = new InitialContext(env); //OLD
InitialContext ic = new InitialContext(); //NEW

原因是当 Shiro 尝试查找“”realms/ShiroRealm”时,它将使用没有环境参数的 InitialContext 来完成。

如果您定义的环境是必需的,您将必须创建一个 RealmFactory 来为 Shiro 提供相同的 属性。

package com.acme.realm.jndi;

import java.util.Properties;

import javax.naming.Context;

public class WASJndiRealmFactory extends JndiRealmFactory {

    @Override
    public void setJndiNames (String commaDelimited) throws IllegalStateException {
        Properties p = new Properties();
        p.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
        setJndiEnvironment(p);
        super.setJndiNames(commaDelimited);
    }
}

然后您必须更新 'shiro.ini' 以引用新的 RealmFactory。

[main]
realmFactory = com.acme.realm.jndi.WASJndiRealmFactory

我偶然浏览了这个有点过时的问题。 我无法配置 Shiro 使其与 WAS 一起工作。相反,我手动将 "scopes" 都需要的公共数据放入 JNDI 上下文中。 这样我就可以在 Shiro 中查找实际应用程序需要的东西。
使用此解决方案,不再需要 ShiroStartup。