gpt4 book ai didi

java - dropwizard hibernate 使用服务器内部的资源

转载 作者:行者123 更新时间:2023-12-02 03:17:30 26 4
gpt4 key购买 nike

我是dropwizard的新手,我正尝试创建一个从用户获取凭据的Authenticator,然后它使用我在UserResouce类中实现的rest api getUser方法来获取具有凭据中用户名的用户db users表。但是在我的autheticator类中,我在弄清楚如何使用用户资源功能来吸引用户方面遇到了麻烦。

我正在尝试做这样的事情:

public List<com.amitbaz.tss.db.User> getUsersFromDB(String username){

SessionFactory sessionFactory = TradingSystemServerApplication.hibernateBundle.getSessionFactory();
UserDAO userDAO = new UserDAO(sessionFactory);
List<com.amitbaz.tss.db.User> user = userDAO.getUser(username);
logger.debug(user.toString());
return user;
}


在身份验证器中并从authenticte函数调用它,但它说没有会话绑定...

编辑:

好吧,经过深思熟虑,我明白了这一点:
我是使用BasicCredentials和的dropwizard身份验证器和授权者实现。

验证者(不要介意VALID_USER的事情。):

package com.amitbaz.tss.auth;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import javax.persistence.NamedQuery;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amitbaz.tss.TradingSystemServerApplication;
import com.amitbaz.tss.db.UserDAO;
import com.amitbaz.tss.db.UserResource;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;

public class TradingSystemServerAuthenticator implements Authenticator<BasicCredentials, User> {

private Logger logger = LoggerFactory.getLogger(TradingSystemServerAuthenticator.class);

private static final Map<String, Set<String>> VALID_USERS = ImmutableMap.of(
"guest", ImmutableSet.of(),
"amit", ImmutableSet.of("admin"),
"stav", ImmutableSet.of("broker")
);

private UserDAO userDAO;

public TradingSystemServerAuthenticator(UserDAO userDAO) {
// TODO Auto-generated constructor stub
this.userDAO = userDAO;
}

@Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
// TODO Auto-generated method stub
List<com.amitbaz.tss.db.User> user = userDAO.getUser(credentials.getUsername());
logger.debug(user.toString());
if("amit".equals(credentials.getPassword())){
return Optional.of(new User(credentials.getUsername(), VALID_USERS.get(credentials.getUsername())));
}
return Optional.empty();
}

}


授权人:

package com.amitbaz.tss.auth;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amitbaz.tss.db.UserDAO;

import io.dropwizard.auth.Authorizer;

public class TradingSystemServerAuthorizer implements Authorizer<User>{

private Logger logger = LoggerFactory.getLogger(TradingSystemServerAuthorizer.class);

private UserDAO userDAO;



public TradingSystemServerAuthorizer(UserDAO userDAO) {
super();
this.userDAO = userDAO;
}



@Override
public boolean authorize(User user, String role) {
// TODO Auto-generated method stub
logger.debug(userDAO.getUser(user.getName()).toString());
return user.getName().equals("amit") && user.getRole().contains(new String("admin"));
}

}


现在,在我的Application类中,执行以下操作:

package com.amitbaz.tss;


import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amitbaz.tss.auth.TradingSystemServerAuthenticator;
import com.amitbaz.tss.auth.TradingSystemServerAuthorizer;
import com.amitbaz.tss.auth.User;
import com.amitbaz.tss.db.Broker;
import com.amitbaz.tss.db.BrokerDAO;
import com.amitbaz.tss.db.BrokerResource;
import com.amitbaz.tss.db.Contact;
import com.amitbaz.tss.db.ContactDAO;
import com.amitbaz.tss.db.ContactResource;
import com.amitbaz.tss.db.Product;
import com.amitbaz.tss.db.ProductDAO;
import com.amitbaz.tss.db.ProductResource;
import com.amitbaz.tss.db.Test;
import com.amitbaz.tss.db.TestDAO;
import com.amitbaz.tss.db.TestResource;
import com.amitbaz.tss.db.Transaction;
import com.amitbaz.tss.db.TransactionDAO;
import com.amitbaz.tss.db.TransactionResource;
import com.amitbaz.tss.db.UserDAO;
import com.amitbaz.tss.db.UserResource;
import com.amitbaz.tss.db.UserRole;
import com.amitbaz.tss.db.UserRoleDAO;
import com.amitbaz.tss.db.UserRoleResource;
import com.amitbaz.tss.db.Website;
import com.amitbaz.tss.db.WebsiteDAO;
import com.amitbaz.tss.db.WebsiteResource;

import io.dropwizard.Application;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import javassist.tools.web.Webserver;

public class TradingSystemServerApplication extends Application<TradingSystemServerConfiguration>{

public static void main(String[] args) throws Exception{
new TradingSystemServerApplication().run(args);
}

public final static HibernateBundle<TradingSystemServerConfiguration> hibernateBundle
= new HibernateBundle<TradingSystemServerConfiguration>(
Test.class,Broker.class, com.amitbaz.tss.db.User.class, UserRole.class
,Product.class, Transaction.class, Website.class, Contact.class
) {
@Override
public DataSourceFactory getDataSourceFactory(
TradingSystemServerConfiguration configuration
) {
return configuration.getDataSourceFactory();
}
};

final Logger logger = LoggerFactory.getLogger(TradingSystemServerApplication.class);

@Override
public void initialize(
final Bootstrap<TradingSystemServerConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle);
}

@Override
public void run(TradingSystemServerConfiguration config, Environment env) throws Exception {
final UserDAO userDAO = new UserDAO(hibernateBundle.getSessionFactory());
final UserRoleDAO userRoleDAO = new
env.jersey().register(new UserResource(userDAO));

/...
BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new TradingSystemServerAuthenticator(userDAO))
.setAuthorizer(new TradingSystemServerAuthorizer(userDAO))
.setRealm("Authetication Required")
.buildAuthFilter()));
env.jersey().register(RolesAllowedDynamicFeature.class);
env.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));

}

}


我在其余api方法之一上使用了@RolesAllowed(“ role_name”)批注,而我尝试测试身份验证。

现在,当我尝试对此进行测试并向该其余api方法发出请求时,我
得到错误 No session currently bound to execution context我在身份验证器和授权者中执行userDAO.getUser(...)

编辑2:

UserDAO的实现:

package com.amitbaz.tss.db;

import java.util.List;

import org.hibernate.SessionFactory;

import io.dropwizard.hibernate.AbstractDAO;

public class UserDAO extends AbstractDAO<User>{

public UserDAO(SessionFactory sessionFactory) {
super(sessionFactory);
// TODO Auto-generated constructor stub
}

public List<User> getUser(String username){
return list(namedQuery("com.amitbaz.tss.db.user.getUser")
.setParameter("username", username));
}

}


编辑3:

添加了@UnitOfWork以对方法进行身份验证和授权。

按如下方式注册它们(注意hibernateBundle和run方法中的更改):
包com.amitbaz.tss;

import javax.servlet.ServletRegistration;

import org.atmosphere.cpr.ApplicationConfig;
import org.atmosphere.cpr.AtmosphereServlet;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amitbaz.tss.auth.TradingSystemServerAuthenticator;
import com.amitbaz.tss.auth.TradingSystemServerAuthorizer;
import com.amitbaz.tss.auth.User;
import com.amitbaz.tss.db.Broker;
import com.amitbaz.tss.db.BrokerDAO;
import com.amitbaz.tss.db.BrokerResource;
import com.amitbaz.tss.db.Contact;
import com.amitbaz.tss.db.ContactDAO;
import com.amitbaz.tss.db.ContactResource;
import com.amitbaz.tss.db.Product;
import com.amitbaz.tss.db.ProductDAO;
import com.amitbaz.tss.db.ProductResource;
import com.amitbaz.tss.db.Test;
import com.amitbaz.tss.db.TestDAO;
import com.amitbaz.tss.db.TestResource;
import com.amitbaz.tss.db.Transaction;
import com.amitbaz.tss.db.TransactionDAO;
import com.amitbaz.tss.db.TransactionResource;
import com.amitbaz.tss.db.UserDAO;
import com.amitbaz.tss.db.UserResource;
import com.amitbaz.tss.db.UserRole;
import com.amitbaz.tss.db.UserRoleDAO;
import com.amitbaz.tss.db.UserRoleResource;
import com.amitbaz.tss.db.Website;
import com.amitbaz.tss.db.WebsiteDAO;
import com.amitbaz.tss.db.WebsiteResource;

import io.dropwizard.Application;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import javassist.tools.web.Webserver;

public class TradingSystemServerApplication extends Application<TradingSystemServerConfiguration>{

public static void main(String[] args) throws Exception{
new TradingSystemServerApplication().run(args);
}

public final static HibernateBundle<TradingSystemServerConfiguration> hibernateBundle
= new HibernateBundle<TradingSystemServerConfiguration>(
Test.class,Broker.class, com.amitbaz.tss.db.User.class, UserRole.class
,Product.class, Transaction.class, Website.class, Contact.class
,TradingSystemServerAuthenticator.class, TradingSystemServerAuthorizer.class
) {
@Override
public DataSourceFactory getDataSourceFactory(
TradingSystemServerConfiguration configuration
) {
return configuration.getDataSourceFactory();
}
};

final Logger logger = LoggerFactory.getLogger(TradingSystemServerApplication.class);

@Override
public void initialize(
final Bootstrap<TradingSystemServerConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle);
}

@Override
public void run(TradingSystemServerConfiguration config, Environment env) throws Exception {
final UserDAO userDAO = new UserDAO(hibernateBundle.getSessionFactory());
final UserRoleDAO userRoleDAO = new UserRoleDAO(hibernateBundle.getSessionFactory());

final TradingSystemServerAuthorizer authorizer = new TradingSystemServerAuthorizer(userDAO);
final TradingSystemServerAuthenticator authenticator = new TradingSystemServerAuthenticator(userDAO);

env.jersey().register(new UserResource(userDAO));
env.jersey().register(new UserRoleResource(userRoleDAO));

env.jersey().register(authorizer);
env.jersey().register(authenticator);

env.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(authenticator)
.setAuthorizer(authorizer)
.setRealm("Authetication Required")
.buildAuthFilter()));
env.jersey().register(RolesAllowedDynamicFeature.class);
env.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));


}

最佳答案

您的方法看起来像一个设计问题。我看到的问题是,您正在尝试通过REST与您的应用程序中已经可以访问的服务集成。这增加了很多开销并使事情复杂化。

幸运的是,DW已经有一个完全集成的授权和身份验证系统,正等着您插入。您可以在此处阅读更多信息:http://www.dropwizard.io/1.0.2/docs/manual/auth.html

这里要注意的基本事情是您应该将资源使用的服务与资源分开。以您的情况为例,例如UserDao,或者您可以将其拆分为UserService和UserResource,其中UserService提供对数据库层的访问。完全由您决定。

这是如何使用DW集成身份验证来实现此目的,以及如何进行注册。

在我的示例中,我跳过了Hibernate方面,因为它不太相关。您可以在这里阅读有关信息:http://www.dropwizard.io/1.0.2/docs/manual/hibernate.html

这是我的代码:

public class AuthenticatorTest extends io.dropwizard.Application<Configuration> {

@Override
public void run(Configuration configuration, Environment environment) throws Exception {
// register resource
environment.jersey().register(MyHelloResource.class);

// create the dao + dependencies
UserDao dao = new UserDao(null);

// register new authenticator
environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Principal>()
.setAuthenticator(new UserAuth(dao)).setRealm("SUPER SECRET STUFF").buildAuthFilter()));

// enables authentication via filter
environment.jersey().register(RolesAllowedDynamicFeature.class);
}

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

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

@GET
@Path("asd")
@PermitAll
public String test(String x) {
return "Hello";
}

}


public static class UserAuth implements Authenticator<BasicCredentials, Principal> {
private UserDao dao;

public UserAuth(UserDao dao) {
this.dao = dao;
}

@Override
public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException {
String user = dao.getUser();
return Optional.of(new Principal() {
@Override
public String getName() {
return user;
}

});
}
}

public static class UserDao {

private SessionFactory s;

public UserDao(final SessionFactory s) {
this.s = s;
}

public String getUser() {
return "pandaadb";
}
}

}


这就是我们正在做的事情的分解。

首先,按照文档,您将在所示的bootstrap方法中注册 HibernateBundle。这使您可以访问进行身份验证所需的 SessionFactory

您的资源方法将使用Java安全注释进行注释。我正在使用 PermitAll,因为我无视角色。

然后,在run方法中,创建 DAO,注册资源并使用DW构建器添加所需的过滤器和 Authenticator。这是专门针对 BasicCredentials的,但是没有什么可以阻止您对此进行任何类型的筛选。 DW已经支持Ldap(具有不同的依赖性),Basic Auth等功能。

现在,由于在run方法中创建了bean,并且在bootstrap方法中添加了Hibernate捆绑包,因此您可以访问 SessionFactory并可以相应地实例化 DAO。无需传递它。

您也不必执行任何其他休息请求即可访问您的用户(尽管万一您需要外部访问,也没有什么阻止您添加该资源的。)

综上所述,重要的部分是:


向您的资源添加安全注释(例如 PermitAll以允许所有角色)
添加使用您的DAO的身份验证器实现(在我的情况下为 UserAuth
用dropwizard提供的run方法实例化它,并在jersey环境中注册它。


注意,这需要您的用户实现 javax.security.Principal接口。通常,这不是一个坏主意,因为许多安全框架都在使用此功能。

这也为您提供了有关DW的更多选择。

您可以添加 Authorization实现和过滤器,并且可以通过添加带 @Auth注释的对象(请参阅文档)将User对象注入任何资源方法中。

最后,从上面对独立应用程序进行测试:

artur@pandaadb:~$ curl "localhost:9085/api/test/asd" -v 
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9085 (#0)
> GET /api/test/asd HTTP/1.1
> Host: localhost:9085
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Date: Mon, 17 Oct 2016 10:45:51 GMT
< WWW-Authenticate: Basic realm="SUPER SECRET STUFF"
< Content-Type: text/plain
< Content-Length: 49
<
* Connection #0 to host localhost left intact
Credentials are required to access this resource.

artur@pandaadb:~$ curl "localhost:9085/api/test/asd" -H "Authorization: Basic dXNlcjpwYXNz" -v
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9085 (#0)
> GET /api/test/asd HTTP/1.1
> Host: localhost:9085
> User-Agent: curl/7.47.0
> Accept: */*
> Authorization: Basic dXNlcjpwYXNz
>
< HTTP/1.1 200 OK
< Date: Mon, 17 Oct 2016 10:46:11 GMT
< Content-Type: application/json
< Vary: Accept-Encoding
< Content-Length: 5
<
* Connection #0 to host localhost left intact
Helloartur


希望这对您的问题有所帮助。

当然,您不需要使用DW方法进行身份验证。但是,我建议您沿着那条路走,因为您将获得更多的支持和很多其他东西。

但是,您应该重新考虑的一件事(如果您不使用DW)是不对Filter进行卷曲请求。而是在run方法中实例化它,然后将该实例传递给您的Filter。

还要注意,如果用DW注册DAO(如在休眠文档中所见),则可以使用 @Inject将DAO注入需要使用它的Filter类中。

是的,我认为这就是您需要的所有信息:)

如果您有任何问题,请告诉我,

阿图尔

编辑:

我正在编辑,是因为我在上面写了很多内容,但又不想遍历它。

我设置了Hibernate进行测试。您看到问题的原因是因为UnitOfWork已绑定到请求范围。但是,资源注释在调用过滤器后匹配(因为在执行该方法之前需要进行身份验证)。这就是为什么您没有会议。

这是解决方案。

在您的run方法中,为您的auth实现注册一个代理:

UnitOfWorkAwareProxyFactory fac = new UnitOfWorkAwareProxyFactory(hibernate);

UserAuth proxy = fac.create(UserAuth.class, UserDao.class, dao);

environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Principal>()
.setAuthenticator(proxy).setRealm("SUPER SECRET STUFF").buildAuthFilter()));


这将围绕UserAuth类创建一个代理,以便它知道UnitOfWork批注。

在您的UserAuth类(或我的类)中,您可以执行以下操作:

public static class UserAuth implements Authenticator<BasicCredentials, Principal> {
private UserDao dao;

public UserAuth(UserDao dao) {
this.dao = dao;
}

@Override
@UnitOfWork
public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException {
String user = dao.getUser();
return Optional.of(new Principal() {
@Override
public String getName() {
return user;
}

});
}
}


注意身份验证上的UnitOfWork批注。现在,这将为您打开一个新会话。请确保仔细阅读UnitOfWork,因为它可能会有(或没有)棘手的副作用,具体取决于您的使用方式。

最后,这允许我的dao在现有会话上与数据库进行对话。

问候,

阿图尔

关于java - dropwizard hibernate 使用服务器内部的资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40080928/

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