【问题标题】:JPA - Using Multiple data sources to define access controlJPA - 使用多个数据源来定义访问控制
【发布时间】:2012-06-28 10:38:41
【问题描述】:

我对 JPA 和 JSF 完全陌生,希望您能帮助我解决我的问题。 我的应用程序是使用 JSF 2.0 框架构建的,使用在 Glassfish 3+、MySQL 上运行的 JPA 2.0/EclipseLink。

我使用数据源设置了一个名为“loginPU”的持久性单元:“jdbc/loginDataSource” “jdbc/loginDataSource”使用“login1”(在mysql.user表中定义)连接到MySQL,并且只能访问customer.usercustomer.roles表,只有选择权限.

我在 Glassfish JDBC 资源中创建了另外 2 个数据源“jdbc/admin”和“jdbc/staff”,它们都具有不同的权限

登录/认证场景为:

  1. 使用基于表单的身份验证(用户名和密码)进行用户登录
  2. 使用持久化单元“loginPU”和“jdbc/loginDataSource”创建EntityManageFactory
  3. 创建查询以检索用户角色
  4. 如果用户角色是 admin,则使用“jdbc/admin”数据源进行连接
  5. 如果用户角色是人员,则使用“jdbc/staff”数据源进行连接

我上面第 2 项的代码如下所示:

Map properties = new HashMap(); 
properties.put(TRANSACTION_TYPE, "JTA");

// Configure the internal EclipseLink connection pool
properties.put(JDBC_DRIVER, "com.mysql.jdbc.Driver");
properties.put(JDBC_URL, "jdbc:mysql://localhost:3306/customer");
properties.put(JDBC_USER, "login1");
properties.put(JDBC_PASSWORD, "login1");
properties.put(JTA_DATASOURCE, "jdbc/loginDataSource");

EntityManageFactory emf = Persistence.createEntityManagerFactory("loginPU",properties);

我什至将我的 EntityManagerFactory 保存在会话属性中并在 JpaController 类中检索它

//save into session
session.setAttribute("entityManagerFactory", emf);

//retrieved in JpaController
public EntityManagerFactory getEmf() {

        HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        HttpSession s = request.getSession(true);
        try {
            emf = (EntityManagerFactory) s.getAttribute("entityManagerFactory");
        } catch(NullPointerException ne){
            System.out.println("EMF Exception: "+ne);
        }

        return emf;
    }

问题:我怎样才能达到第 4 或第 5?有没有可能 做?是否可以将任一数据源分配给“loginPU” 持久化单元?我设法使用 loginPU 和 jdbc/loginDataSource 建立连接 然后使用 jdbc/admin 数据源连接,但是当我访问其他 实体,它会抛出错误并默认为 jdbc/loginDataSource

注意: 我正在使用由 netbeans 创建的 JpaController 类,以及会话 bean 来管理实体。 我的 JpaController 类使用

@Resource private UserTransaction utx;
@PersistenceUnit private EntityManagerFactory emf;

我的会话 bean 都是 @Stateless,我尝试使用 @PersistenceContext 与 unitName 和没有 unitName 但没有运气

@PersistenceContext
private EntityManager em;

我尝试在persistence.xml中使用多个持久化单元,希望根据角色使用持久化单元名称连接用户,但部署到服务器时出错。

我读到了application-managed persistencecontainer-managed,我想我想要实现的是使用应用程序管理,但不知道该怎么做。

如果我要使用容器管理的持久性,是否可以使用多个数据源?非常感谢任何建议。

提前感谢您的任何 cmets 或建议。

[已解决]

  1. 首先我将我的 persistence.xml 定义如下:

    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
        <persistence-unit name="mdbAdminPU" >
            <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
            <jta-data-source>jdbc/login</jta-data-source>
            <exclude-unlisted-classes>false</exclude-unlisted-classes>
        </persistence-unit>
    </persistence>
    
  2. 我的会话 bean 中没有使用任何 @PersistenceUnit 或 @PersistenceContext。(我使用的是 Netbeans,这些 bean 是在我从实体类创建 JSF 页面时创建的)

  3. 在所有会话 bean 中,它们看起来像这样:

    @Stateless
    public class UserFacade extends AbstractFacade<User> {
    
        @Override
        protected EntityManager getEntityManager() {
            HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
            EntityManagerFactory emf = (EntityManagerFactory) session.getAttribute("entityManagerFactory");
            EntityManager em = emf.createEntityManager(); 
            return em;
        }
    
        public UserFacade() {
            super(User.class);
        }
    }
    
  4. 上面的登录场景(5项)变成了7:

  1. 使用基于表单的身份验证(用户名和密码)进行用户登录
  2. 使用持久化单元“loginPU”和“jdbc/loginDataSource”创建EntityManageFactory
  3. 创建查询以检索用户角色
  4. 如果用户角色是 admin,则使用“jdbc/admin”数据源进行连接
  5. 如果用户角色是人员,则使用“jdbc/staff”数据源进行连接

  1. 删除或清除在第 2 项中创建的 EntityManagerFactory 使用 emf.close();
  2. 保留在项目 4 或 5 中创建的新 EntityManagerFactory HttpSession

【问题讨论】:

  • 我不明白您为什么要使用这种繁琐的方式来获取EntityManagerFactory:这是您尝试动态检索PersistenceContext 的一种方式吗?
  • 我不确定最好的方法是什么,感谢您指出它很麻烦。非常感谢您的指导。

标签: jpa glassfish eclipselink persistence-unit


【解决方案1】:

如果您需要三个不同的登录名,最好在您的 persistence.xml 中使用三个独立的持久性单元。或者只需一次登录即可获得完全访问权限并验证您的应用程序的安全性(无论如何您似乎都在做部分工作)。

您在部署时遇到了什么错误?

您可以使用 EclipseLink 中的一个持久性单元来完成此操作,但它涉及更多,并且您不能使用容器管理的实体管理器。您将注入一个@PersistenceUnit (EntityManagerFactory) 而不是@PersistenceContext (EntityManager),然后您需要将新的登录参数传递给createEntityManager()。您需要将“eclipselink.jdbc.exclusive-connection.mode”属性设置为“Always”(或“Isolated”并隔离安全数据)。

看, http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing

【讨论】:

  • 感谢您的回答,詹姆斯。你的意思是我可以使用相同的持久化单元和相同的数据源,唯一不同的是在创建EntityManager时传递不同的属性(用户和密码)?我会试试这个并发布我的结果。干杯
  • 这对你来说可能听起来很愚蠢。我从我的 jpaController 创建 EntityManager,并传递“admin”用户的属性,然后使用 EM 来 createQuery,但错误消息显示“SELECT command denied to user 'login1'@'localhost' for table 'user_activity'”表示 EM 仍默认为“login1”,这是我第一次用来进行身份验证的用户。
猜你喜欢
  • 2010-12-11
相关资源
最近更新 更多