2016-02-04 2 views
1

В нашем приложении мы используем диспетчер пулов Spring Boot и Tomcat. Соединения приобретаются с использованием конкретного пользователя. Таким образом, любой, кто подключается к приложению независимо от имени пользователя, мы используем имя пользователя приложения для сохранения данных. Однако для определенной операции мы хотим олицетворять использование команды MSSQL 'setuser'. Как мы можем достичь этого?Как использовать олицетворение пользователя MSSQL в Java с помощью пула соединений Tomcat?

Чтобы сделать его более ясным, что мы хотим, это своего рода перехватчик, так что перед выполнением SQL заявление, мы можем выполнить следующую команду:

setuser 'user_a' 

и перед выпуском соединения мы можем выполнить:

setuser 

так, что олицетворение сбрасывается.
Предположим, что в перехватчике мы знаем, должно ли соединение выдаваться или нет.

ответ

0

Я решил это с помощью перехватчика Jdbc. Метод в перехватчике будет вызываться всякий раз, когда соединение заимствовано из пула. Пожалуйста, проверьте ссылку ниже:

Jdbc interceptor

Вот мой код:

public class ImpersonatorJdbcInterceptor extends JdbcInterceptor { 
    private static final Logger logger = LoggerFactory.getLogger(ImpersonatorJdbcInterceptor.class); 

    /** 
    * This method gets invoked whenever a connection is borrowed from the pool. 
    * Since releasing a connection back to pool cannot be intercepted in this method we 
    * need to first reset the previous impersonation. 
    * {@inheritDoc} 
    */ 
    @Override 
    public void reset(ConnectionPool connectionPool, PooledConnection pooledConnection) { 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
     logger.debug("A connection is borrowed from the pool by {}", (auth != null ? auth.getName() : "null")); 
     Connection conn = pooledConnection.getConnection(); 

     /* 
     * Note: 
     * 1 We can't impersonate current user 
     * 2 We can't impersonate a user when the current session is already impersonated. 
     * 3 'setuser' without username resets back to original user who has created the connection 
     * 4 The user must have the right permission to be able to impersonate 
     * 5 It is the caller's responsibility to close the connection; We only close the connection if this execution fails 
     */ 
     try (PreparedStatement prep = conn.prepareStatement(auth != null ? "setuser; setuser ?" : "setuser")) { 
      if(auth != null) { 
       prep.setString(1, auth.getName()); 
      } 
      prep.execute(); 
     } catch (SQLException e) { 
      logger.error("Impersonation failed. Please check permission for 'setuser': " + (auth != null ? auth.getName() : "null"), e); 
      close(conn); 
      throw new IllegalStateException("Oops! Cannot execute statements, please contact the administrator", e); 
     } 
    } 

    /** 
    * Closes the statement and rolls back only if something goes wrong. 
    * @param conn 
    */ 
    private void close(Connection conn) { 
     try { 
      if(conn != null && !conn.isClosed()) { 
       conn.rollback(); 
       conn.close(); 
      } 
     } catch (SQLException e) { 
      logger.error("Something went wrong and the connection cannot be closed", e); 
      //the caller will throw exception 
     } 
    } 

} 
+0

Care поделиться своим перехватчик? –

+0

Да, конечно ... обновлено. Это хорошо работает с JPA – xbmono

+0

, откуда вы узнали, что контекст безопасности возвращается после того, как соединение возвращается в пул? –