gpt4 book ai didi

hibernate - Dropwizard & Hibernate - 当前没有 session 绑定(bind)到执行上下文

转载 作者:行者123 更新时间:2023-12-05 00:52:45 24 4
gpt4 key购买 nike

我想我很清楚我的问题出在哪里,但完全不知道如何解决它......

这是我在 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));
}

现在,正如您在此处看到的,我正在将我的 User dao 传递给我的身份 validator ......
我在网上看到的任何教程都没有这样做,这是因为每个在线教程都使用硬编码值,而不是展示如何查询数据库。

也就是说,这就是我尝试进行身份验证的方式...
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 将我的代码粘贴到这里,它只是表现不佳 - 无论如何,当我尝试运行这个应用程序时,身份 validator 告诉我:
No session currently bound to execution context

这是踢球者,我知道这只是为了我收到此错误的安全方面,因为如果我从 Application 类中删除安全线并运行它,我仍然可以点击我的创建用户端点(也使用这个DAO)并且效果很好。

所以我的问题真的是 - 我是否打算在身份 validator 中使用该 dao?如果不是,我到底要如何查询数据库?

如果我是,那我哪里错了?

提前致谢。

最佳答案

首先,你的问题:

来自 DW 文档:

Currently creating transactions with the @UnitOfWork annotation works out-of-box only for resources managed by Jersey. If you want to use it outside Jersey resources, e.g. in authenticators, you should instantiate your class with UnitOfWorkAwareProxyFactory.



使用您的代码,您可以创建一个 Authenticator但是您永远不会将其与 hibernate session Hook 。 Authenticator 会怎样?知道何时为 DAO 打开一个新 session 操作?这是由 UnitOfWork 完成的。机制。然而,这目前仅适用于 Jersey 资源,并且需要为任何其他想要参与其中的类启用。

所以,幸运的是文档给了我们一个准确的 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 db 设置的最小 DW 应用程序。您必须应用配置更改才能启动(并更改服务器配置文件)

这是做什么的:
  • 创建提供 DataSourceFactory 的 hibernate 包
  • 创建 DAO
  • 创建 Authenticator作为代理
  • 将所有这些连接在一起

  • 重要的位是:
    MyAuthenticator proxyAuth = new UnitOfWorkAwareProxyFactory(hibernate).create(MyAuthenticator.class, MyDao.class, dao);

    这会为您创建一个知道 UnitOfWork 的代理。注解。它启用 Authenticator Hook (我相信)将根据请求打开和关闭 session 的事件系统。

    然后,您在 AuthDynamicFeature 中使用该代理。

    最后,在您的 Authenticator您必须告诉它在执行身份验证时打开一个新的 Session,例如:
    @Override
    @UnitOfWork
    public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException {
    dao.get();
    return Optional.empty();
    }

    现在所有这些都将毫无异常(exception)地工作:
    curl user:pass@localhost:9085/api/test/test 
    Credentials are required to access this resource.

    至于你的最后一个问题:

    I'm actually more fluent with spring do you think it would be a good idea to switch instead of dealing with this constantly?



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

    我希望这可以解决问题并让您开始:)

    问候,

    阿图尔

    关于hibernate - Dropwizard & Hibernate - 当前没有 session 绑定(bind)到执行上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42384671/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com