How does the postgresql (set role user) command use in SSM projects?

岁酱吖の 提交于 2020-01-25 07:51:17

问题


Now the project is using springmvc+ spring + mybatis + druid + postgresql The users in the project correspond to the users in the database, so each time you run SQL, you switch the users with the (set role user) command and then perform the crud operations of the database.

My question: Because there are many connections in the connection pool, the first step is to get the connection of the database, then switch users, and then perform the operation of business SQL on the database. But I don't know which part of the project this logic should be processed, because the connection of the connection pool and the execution of SQL are implemented by the underlying code. Do you have any good plans? Can you provide me with a complete demo, such as the following operations:

Step 1, get the user's name from spring security (or shiro).

Step 2, Get the connection currently using the database from the connection pool.

Step 3, execute SQL (set role user) to switch roles.

Step 4, perform crud operation.

Step 5, Reset the database connection(reset role)


回答1:


Here is a simple way to do what you need with the help of mybatis-spring.

Unless you already use mybatis-spring the first step would be to change the configuration of your project so that you obtain SqlSessionFactory using org.mybatis.spring.SqlSessionFactoryBean provided by mybatis-spring.

The next step is the implementation of setting/resetting the user role for the connection. In mybatis the connection lifecycle is controlled by the class implementing org.apache.ibatis.transaction.Transaction interface. The instance of this class is used by the query executor to get the connection.

In a nutshell you need to create your own implementation of this class and configure mybatis to use it.

Your implementation can be based on the SpringManagedTransaction from mybatis-spring and would look something like:

import org.springframework.security.core.Authentication;

class UserRoleAwareSpringManagedTransaction extends SpringManagedTransaction {

  public UserRoleAwareSpringManagedTransaction(DataSource dataSource) {
    super(dataSource);
  }

  @Override
  public Connection getConnection() throws SQLException {
    Connection connection = getCurrentConnection();
    setUserRole(connection);
    return connection;
  }

  private Connection getCurrentConnection() {
    return super.getConnection();
  }

  @Override
  public void close() throws SQLException {
    resetUserRole(getCurrentConnection());
    super.close();
  }  

  private void setUserRole(Connection connection) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String username = authentication.getName();
    Statement statement = connection.createStatement();
    try {
      // note that this direct usage of usernmae is a subject for SQL injection
      // so you need to use the suggestion from
      // https://stackoverflow.com/questions/2998597/switch-role-after-connecting-to-database
      // about encoding of the username
      statement.execute("set role '" + username + "'");
    } finally {
      statement.close();
    }
  }

  private void resetUserRole(Connection connection) {
    Statement statement = connection.createStatement();
    try {
      statement.execute("reset role");
    } finally {
      statement.close();
    }
  }

}

Now you need to configure mybatis to use you Transaction implementation. For this you need to implement TransactionFactory similar to org.mybatis.spring.transaction.SpringManagedTransactionFactory provided by mybatis-spring:

public class UserRoleAwareSpringManagedTransactionFactory implements TransactionFactory {
  @Override
  public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
    return new UserRoleAwareSpringManagedTransaction(dataSource);
  }
  @Override
  public Transaction newTransaction(Connection conn) {
    throw new UnsupportedOperationException("New Spring transactions require a DataSource");
  }
  @Override
  public void setProperties(Properties props) {
  }
}

And then define a bean of type UserRoleAwareSpringManagedTransactionFactory in your spring context and inject it into transactionFactory property of the SqlSessionFactoryBeen in your spring context.

Now every time mybatis obtains a Connection the implementation of Transaction will set the current spring security user to set the role.




回答2:


Best practice is that database users are applications. Application users' access to particular data/resource should be controlled in the application. Applications should not rely on database to restrict data/resource access. Therefore, application users should not have different roles in database. An application should use only a single database user account.

Spring is manifestation of best practices. Therefore, Spring does not implement this functionality. If you want such functionality, you need to hack.

Referring to this, your best bet is to:

@Autowired JdbcTemplate jdbcTemplate; 

// ...

public runPerUserSql() {

    jdbcTemplate.execute("set role user 'user_1';");
    jdbcTemplate.execute("SELECT 1;");

}

I still do not have much confidence in this. Unless you are writing a pgAdmin webapp for multiple users, you should re-consider your approach and design.



来源:https://stackoverflow.com/questions/57797538/how-does-the-postgresql-set-role-user-command-use-in-ssm-projects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!