Spring Security查询无效的列索引异常但在Oracle上工作

问题描述

我正在使用Spring Security 4,即使我在PL / sql中正常运行,输入的查询也无法正常工作。

我想访问ROLETYPE表。这些表与主键和外键链接,例如:UTILISATEURS具有POSTES具有ROLES具有RHNOM(角色类型为LIB1

这是查询

 authorities-by-username-query="select LIB1 from RHNOM rh,UTILISATEURS u,POSTES p,ROLES r 
            where u.IDPOSTE = p.ID_POSTE and p.ID_ROLE = r.ID_ROLE and r.ID_TYP_ROLE = rh.IDNOM and u.LOGIN  = ?" />

错误

  Caused by: org.springframework.jdbc.InvalidResultSetAccessException: PreparedStatementCallback; invalid ResultSet access for sql [select LIB1 from RHNOM rh,ROLES r where u.IDPOSTE = p.ID_POSTE and p.ID_ROLE = r.ID_ROLE and r.ID_TYP_ROLE = rh.IDNOM and u.LOGIN = ?]; nested exception is java.sql.sqlException: Index de colonne non valide
    at org.springframework.jdbc.support.sqlErrorCodesqlExceptionTranslator.doTranslate(sqlErrorCodesqlExceptionTranslator.java:235)
    at org.springframework.jdbc.support.AbstractFallbacksqlExceptionTranslator.translate(AbstractFallbacksqlExceptionTranslator.java:73)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:660)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:695)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:727)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:737)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:787)
    at org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl.loadUserAuthorities(JdbcDaoImpl.java:236)
    at org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl.loadUserByUsername(JdbcDaoImpl.java:188)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:114)
    ... 34 more
Caused by: java.sql.sqlException: Index de colonne non valide
    at oracle.jdbc.driver.OracleResultSetImpl.getString(OracleResultSetImpl.java:1277)
    at org.apache.commons.dbcp.DelegatingResultSet.getString(DelegatingResultSet.java:213)
    at org.apache.commons.dbcp.DelegatingResultSet.getString(DelegatingResultSet.java:213)
    at org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl$2.mapRow(JdbcDaoImpl.java:240)
    at org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl$2.mapRow(JdbcDaoImpl.java:237)
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:93)
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60)
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:708)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:644)
    ... 41 more

解决方法

您需要匹配Spring Security期望的所有列,对于authorities-by-username-queryusername,authority,请参见<jdbc-user-service>和检索实现:

protected List<GrantedAuthority> loadUserAuthorities(String username) {
  return getJdbcTemplate().query(this.authoritiesByUsernameQuery,new String[] { username },new RowMapper<GrantedAuthority>() {
              @Override
              public GrantedAuthority mapRow(ResultSet rs,int rowNum)
                      throws SQLException {
                  String roleName = JdbcDaoImpl.this.rolePrefix + rs.getString(2);

                  return new SimpleGrantedAuthority(roleName);
              }
          });
}

来自JdbcDaoImpl in Spring Security 4.2.18

如您所见,您实际上并不需要第一列作为用户名(因为它不会被检索),但是角色(权限)必须是第二列,因为它是通过索引检索的。

简而言之,您需要将查询更改为以下内容:

select u.LOGIN,LIB1 from ...