简体   繁体   English

HK2依赖注入Jersey 2和Apache Shiro

[英]HK2 dependency injection with Jersey 2 and Apache Shiro

I'm creating a rest api using Jersey 2.5.1. 我正在使用Jersey 2.5.1创建一个rest api。 I'm using HK2 for dependency injection. 我正在使用HK2进行依赖注入。 Later on I decided to use Apache Shiro for authentication and authorization. 后来我决定使用Apache Shiro进行身份验证和授权。

While creating my own custom Shiro Realm I ran into some problems. 在创建我自己的自定义Shiro Realm时遇到了一些问题。 In my realm I wanted to inject a dependency. 在我的领域,我想注入依赖。 However, when I ran my application the dependency was not resolved. 但是,当我运行我的应用程序时,依赖关系未得到解决。

Here is my setup: 这是我的设置:

web.xml web.xml中

<web-app 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/web-app_3_0.xsd"
    version="3.0">

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>MyApplication</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>my.app.api.MyApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>MyApplication</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

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

shiro.ini shiro.ini

[main]

authcBasicRealm = my.app.api.MyCustomRealm
matcher = my.app.api.MyCustomCredentialsMatcher
authcBasicRealm.credentialsMatcher = $matcher
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager

[urls]

/** = authcBasic

MyApplication.java MyApplication.java

public class MyApplication extends ResourceConfig {
   public MyApplication() {
      register(new ApplicationBinder());
      packages(true, "my.app.api");
   }
}

ApplicationBinder.java ApplicationBinder.java

public class ApplicationBinder extends AbstractBinder {
   @Override
   protected void configure() {
      bind(UserDAO.class).to(new TypeLiteral<Dao<User>>(){});
      bind(RealDatasource.class).to(DataSource.class);
   }
}

MyCustomRealm.java MyCustomRealm.java

public class MyCustomRealm extends JdbcRealm {

   @Inject DataSource source;

   public MyCustomRealm() {
      super();
   }

   @PostConstruct
   private void postConstruct() {
      // postConstruct is never executed
      setDataSource(source);
   }
}




So, the problem is that source is not injected in MyCustomRealm. 所以,问题是源不是在MyCustomRealm中注入的。 All other classes that isn't created by Shiro gets its dependencies injected. Shiro不创建的所有其他类都会注入其依赖项。 Could the problem be that Shiro is creating my CustomRealm via the ini file? 可能问题是Shiro是通过ini文件创建我的CustomRealm吗?

One problem I see in MyCustomRealm is that you are expecting DataSource to be filled in at construction time. 我在MyCustomRealm中看到的一个问题是,您希望在构建时填充DataSource。 There are two ways to resolve this issue; 有两种方法可以解决这个问题; one is to use constructor injection and the other is to use a post construct. 一种是使用构造函数注入,另一种是使用post构造。 Here would be using constructor injection: 这里将使用构造函数注入:

public class MyCustomRealm extends JdbcRealm {

   private final DataSource source;

   @Inject
   public MyCustomRealm(DataSource source) {
      super();

      this.source = source;

      // source does not get injected
      setDataSource(source);
   }
}

Here is how you would do it with postConstruct: 以下是使用postConstruct执行此操作的方法:

public class MyCustomRealm extends JdbcRealm {

   @Inject DataSource source;

   public MyCustomRealm() {
      super();
   }

   @javax.annotation.PostConstruct
   private void postConstruct() {
      // source does not get injected
      setDataSource(source);
   }
}

I ran into a similar issue, and, while this is probably no longer an issue for you, I wanted to provide the work-around I used. 我遇到了类似的问题,虽然这可能不再是你的问题,但我想提供我使用的解决方法。

The issue is ownership of MyCustomRealm . 问题是MyCustomRealm所有权。 It is being created by shiro in the org.apache.shiro.web.env.EnvironmentLoaderListener by reading the ini file which is outside the scope of the hk2 provider in the Jersey servlet. 它是由shiro在org.apache.shiro.web.env.EnvironmentLoaderListener通过读取在Jersey servlet中hk2提供程序范围之外的ini文件创建的。

Dependency injection is only done when the object is being provided by hk2's ServiceLocator--shiro has no knowledge of this locator and only constructs an instance of MyCustomRealm with its default constructor. 只有在hk2的ServiceLocator提供对象时才会执行依赖注入 - shiro不了解​​此定位器,只使用其默认构造函数构造MyCustomRealm的实例。

I worked around this by implementing a org.glassfish.jersey.server.spi.ContainerLifecycleListener that gets a handle to the ServiceLocator and shiro's SecurityManager (through the ServletContext which is registered with the ServiceLocator ). 我通过实现一个org.glassfish.jersey.server.spi.ContainerLifecycleListener解决了这个问题,它获取了ServiceLocator和shiro的SecurityManager的句柄(通过在ServiceLocator注册的ServletContext )。 It then manually injects the data into the realm created by shiro. 然后它手动将数据注入shiro创建的领域。

If you're interested, I can post the code as a gist. 如果您有兴趣,我可以将代码作为要点发布。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM