2017-02-22 33 views
3

我想我有一个公平的想法我的问题是什么在这里,但也绝对不知道我怎么可能解决它会...Dropwizard和Hibernate - 没有当前绑定到执行上下文

这是我如何我开始我在dropwizard应用:

@Override 
public void run(ServerConfiguration configuration, Environment environment) 
{ 

    // Setting up the database. 
    final DBIFactory factory = new DBIFactory(); 
    final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "mysql"); 

    //Hibernate 
    final UserDAO dao = new UserDAO(hibernate.getSessionFactory()); 
    environment.jersey().register(new UserResource(dao)); 

    final TemplateHealthCheck healthCheck = new TemplateHealthCheck(configuration.getTemplate()); 

    environment.healthChecks().register("template", healthCheck); 

    // security 
    //****** Dropwizard security - custom classes ***********/ 
    environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>() 
      .setAuthenticator(new BasicAuth(dao)) 
      .setAuthorizer(new BasicAuthorizer()) 
      .setRealm("BASIC-AUTH-REALM") 
      .buildAuthFilter())); 
    environment.jersey().register(RolesAllowedDynamicFeature.class); 
    environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class)); 
} 

现在,你可以看到这里,我通过我的用户DAO到我的认证...... 没有教程,我在网上做到这一点看出来了,这是因为每一个在线教程用途硬编码值而不是显示如何查询数据库。

这就是说,这里是我正在试图验证...

public class BasicAuth implements Authenticator<BasicCredentials, User> { 

UserDAO _userDAO; 
final Encryption enc = new Encryption(); 

public BasicAuth(UserDAO dao) 
{ 
    this._userDAO = dao; 
} 

@Override 
public Optional<User> authenticate(BasicCredentials credentials) 
     throws AuthenticationException { 

    // Get the user record. 
    User requestedUser = _userDAO.findOneByUsername(credentials.getUsername()); 

    if (requestedUser != null) 
    { 
     // check pw. 
     if(enc.compare(credentials.getPassword(), requestedUser.getPassword())) { 
      return Optional.of(requestedUser); 
     } 
     else { 
      return Optional.empty(); 
     } 
    } 
    return Optional.empty(); 
} 
} 

请原谅以上可怕的缺口,我贴我的代码从这里的IntelliJ和它只是不表现很好 - 反正,当我尝试运行此应用程序中,验证告诉我:

No session currently bound to execution context 

这里是踢球的,我知道这仅仅是本作的安全方面,我得到这个错误,因为如果我删除了安全线从应用程序类,并运行它,我仍然可以打我的创建用户端点(也使用此DAO),并且运行良好。

所以我在这里的问题真的是 - 我是否打算在验证器中使用该dao?如果不是,我该怎么查询数据库?

如果我是,那么我会错在哪里?

在此先感谢。

+0

没有太多的时间,现在,但我相信你需要寻找到“工作单位” DW上的注释。他们将球衣上下文连接到休眠 – pandaadb

+0

我的资源调用了这个已经使用@UnitOfWork - 这就是为什么我对此感到困惑。 – MickeyThreeSheds

+1

虽然我看不到任何brdiging。如果球衣不知道你的DAO,只注释资源方法是不够的。你需要阅读http://www.dropwizard.io/1.0.6/docs/manual/hibernate.html#transactional-resource-methods-outside-jersey-resources上的最后一节,它告诉你如何让休眠进入球衣生态系统。关键字:UnitOfWorkAwareProxyFactory – pandaadb

回答

2

首先,您的问题:

从DW文档:

与@UnitOfWork注释目前创建工作事务外的盒子只能由新泽西州管理的资源 。如果您想在Jersey资源外使用它 ,例如在身份验证器中,您应该使用UnitOfWorkAwareProxyFactory实例化您的类。

通过您的代码,您可以创建一个Authenticator,但您永远不会将其挂回到Hibernate会话。 Authenticator如何知道何时开启DAO的新会话以进行操作?这由UnitOfWork机制完成。然而,目前这只适用于泽西岛的资源,并且需要为任何其他希望参与其中的课程启用。

所以,幸运的是Google文档提供了我们这里的确切Authenticator例如: http://www.dropwizard.io/1.0.6/docs/manual/hibernate.html

我不会去复制他们的代码,因为我有一个独立的例子让你玩:

public class HibernateTest extends io.dropwizard.Application<DBConfiguration> { 

    private final HibernateBundle<DBConfiguration> hibernate = new HibernateBundle<DBConfiguration>(Object.class) { 
     @Override 
     public DataSourceFactory getDataSourceFactory(DBConfiguration configuration) { 
      return configuration.getDataSourceFactory(); 
     } 
    }; 

    @Override 
    public void initialize(Bootstrap<DBConfiguration> bootstrap) { 
     super.initialize(bootstrap); 
     bootstrap.addBundle(hibernate); 
    } 

    @Override 
    public void run(DBConfiguration configuration, Environment environment) throws Exception { 
     MyDao dao = new MyDao(hibernate.getSessionFactory()); 
     environment.jersey().register(new MyHelloResource(dao)); 


     // THIS IS ABSOLUTELY CRITICAL 
     MyAuthenticator proxyAuth = new UnitOfWorkAwareProxyFactory(hibernate).create(MyAuthenticator.class, MyDao.class, dao); 

     AuthDynamicFeature authDynamicFeature = new AuthDynamicFeature(
       new BasicCredentialAuthFilter.Builder<Principal>() 
        .setAuthenticator(proxyAuth) 
        .setRealm("SUPER SECRET STUFF") 
        .buildAuthFilter()); 

     environment.jersey().register(authDynamicFeature); 
    } 

    public static void main(String[] args) throws Exception { 
     new HibernateTest().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/db.yaml"); 
    } 

    @Path("test") 
    @Produces(MediaType.APPLICATION_JSON) 
    public static class MyHelloResource { 

     private MyDao dao; 

     public MyHelloResource(MyDao dao) { 
      this.dao = dao; 
     } 

     @GET 
     @Path("/test") 
     @UnitOfWork 
     @PermitAll 
     public Response downloadFile() throws Exception { 
      dao.get(); 
      return Response.ok().build(); 
     } 

    } 

    public static class MyAuthenticator implements Authenticator<BasicCredentials, Principal> { 
     private MyDao dao; 

     MyAuthenticator(MyDao dao) { 
      this.dao = dao; 
     } 

     @Override 
     @UnitOfWork 
     public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException { 
      dao.get(); 
      return Optional.empty(); 
     } 
    } 

    public static class MyDao extends AbstractDAO<Object> { 

     public MyDao(SessionFactory sessionFactory) { 
      super(sessionFactory); 
     } 

     public Object get() { 
      // if not bridged to Jersey this will throw an exception due to session 
      currentSession().createSQLQuery("SELECT 1;").uniqueResult(); 
      return new Object(); 
     } 
    } 

} 

上面的代码在内存中运行一个具有h2数据库设置的最小DW应用程序。你将不得不申请您的配置更改,使其开始(和更改服务器的配置文件)

这样做是:

  1. 创建休眠束供给的DataSourceFactory
  2. 创建DAO
  3. 作为代理
  4. 线创建Authenticator所有的一起

重要的位是:

MyAuthenticator proxyAuth = new UnitOfWorkAwareProxyFactory(hibernate).create(MyAuthenticator.class, MyDao.class, dao); 

这将创建一个代理,你是知道的UnitOfWork注释。它使Authenticator能够挂钩(我相信)事件系统,它可以根据请求打开和关闭会话。

您再使用该代理在AuthDynamicFeature

最后,在Authenticator你必须告诉它打开一个新的会话执行身份验证时,如:

@Override 
     @UnitOfWork 
     public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException { 
      dao.get(); 
      return Optional.empty(); 
     } 

现在,所有的这将工作无异常:

curl user:[email protected]:9085/api/test/test 
Credentials are required to access this resource. 

至于你的最后一个问题:

我实际上比较流利的有春天,你认为这会是一个不错的想法,而不是不断地处理这个问题吗?

我认为这主要是基于意见的,但是:Spring DI!= Jersey DI。你基本上和Spring做同样的事情,你可以桥接Jersey DISpring DI,这样jersey可以访问Spring中的这些bean。但是,所有的session逻辑仍然以相同的方式处理。 Spring只需将显式抽象afaik - 它在创建bean时已经为您创建了代理。所以我认为你不会有这方面的许多优势,并且从个人经验来看,将Spring和Jersey结合起来并不那么容易。依赖关系(spring-jersey-bridge)球衣广告不适用于嵌入式Jetty(如DW设置),而是在启动时挂钩到Servlet(您没有)。这仍然可以工作,但它需要一些黑客来获得该设置。根据我的经验,guice(例如https://github.com/xvik/dropwizard-guicey)更容易和更好地融入数据仓库,并且会给你相同的优势。 Guice显然不会做春天所做的所有事情(Spring也没有做所有Guice所做的事情),因此您可能需要自己做一些研究。

我希望这将清除的东西了,并让你开始:)

问候,

阿图尔

相关问题