簡體   English   中英

Spring Security OAuth2中注入自定義userDetailsS​​ervice的問題

[英]problems injecting custom userDetailsService in Spring Security OAuth2

我正在使用Spring Security OAuth2 2.0.7.RELEASE。 當我使用ORM連接到數據庫並且默認JdbcUserDetailsManager使用jdbc時,我想實現自己的UserDetailsS​​ervice,即

@Service
public class UserService
    implements UserDetailsService {

    @Override
    public UserDetailsService loadUserByUsername(String username) throws UsernameNotFoundException {
        // I tested this logic and works fine so i avoid this lines
        return userDetailsService;
    }
}

此外,我還修改了權限架構,如下所示:

mysql> describe authorities;
+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| authority_id | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| user_id      | bigint(20) unsigned | NO   | MUL | NULL    |                |
| authority    | varchar(256)        | NO   |     | NULL    |                |
+--------------+---------------------+------+-----+---------+----------------+

然后,我像這樣注入我的自定義userDetailsS​​ervice:

@Configuration
@Import(OAuth2SupportConfig.class)
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends
        AuthorizationServerConfigurerAdapter {

  ...    

  @Autowired
  private UserDetailsService userDetailsService

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer    endpoints)
            throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .tokenStore(tokenStore).tokenServices(tokenService);
        endpoints.userDetailsService(userDetailsService); // Inject custom
        endpoints.authorizationCodeServices(authorizationCodeServices);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients)
            throws Exception {
        clients.jdbc(dataSource);
    }
}

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AuthenticationManagerConfiguration
    extends GlobalAuthenticationConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService userService;

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
 auth.jdbcAuthentication().dataSource(this.dataSource).and().userDetailsService(this.userService);// Inject custom
    }
}

如果我使用Grant_type = password發送/ oauth / token請求,則會出現此錯誤

POST /oauth/token HTTP/1.1
Host: localhost:8080
Authorization: Basic aW5kaXJhOnNlY3JldA==
Cache-Control: no-cache
Postman-Token: c89baf37-8ad2-4270-5251-9715bfab470a
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=user&password=pass

(其中對clientId和clientSecret進行編碼)

{
  "error": "unauthorized",
  "error_description": "PreparedStatementCallback; bad SQL grammar [select username,authority from authorities where username = ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'username' in 'field list'"
}

顯然仍在使用默認的JdbcDaoImpl。 實際上,當我開始調試時,發現執行以下步驟:

  1. 對客戶端進行身份驗證(好的,因為我還沒有修改oauth_client_details表)
  2. 使用我的自定義userDetailsS​​ervice對用戶進行身份驗證(好的,已修改users表,但我的自定義userDetailsS​​ervice支持更改)
  3. 使用默認的userDetailsS​​ervice(ERROR)對用戶進行身份驗證

我不知道為什么會這樣。 對我來說,這聽起來像個蟲子。 你有沒有發現什么問題?

您正在使用auth.jdbcAuthentication().dataSource(this.dataSource).and().userDetailsService(‌​this.userService);// Inject custom ,我在這里創建了兩個auth管理器-一個具有默認的JdbcDaoImpldataSource指向this.dataSource和另一個帶有自定義userService 嘗試僅將auth.userDetailsService(this.userService) (我希望userService已將jdbc自動連接到其中)。

這里的重點是.and()用於向身份驗證管理器添加不同的身份驗證配置,而不是配置jdbcAuthentication()

2.0.7當您以授予類型作為password/oauth/token進行POST/GET請求時,它實際上將是ClientDetailsUserDetailsService而不是UserDetailsService

我有類似的問題,這就是我解決的方法:

public class AppClientDetailsUserDetailsService extends ClientDetailsUserDetailsService {
    public AppClientDetailsUserDetailsService(ClientDetailsService clientDetailsService) {
        super(clientDetailsService);
    }
}


public class AppConsumerDetailsService implements ClientDetailsService {

     public ClientDetails loadClientByClientId(String clientId)
            throws OAuth2Exception {
           //some logic
     }
}

<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="authenticationManager"
          entry-point-ref="entryPoint" xmlns="http://www.springframework.org/schema/security"
            >
        <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
        <anonymous enabled="false" />
        <http-basic entry-point-ref="entryPoint" />
        <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />

</http>

<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
      <property name="authenticationManager" ref="authenticationManager" />
    </bean>

authenticationManagerAppClientDetailsUserDetailsService的bean,其構造函數參數為AppConsumerDetailsService

問題是您正在使用默認的JdbcDaoImpl 引起問題的查詢是

public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
        "select username,authority " +
        "from authorities " +
        "where username = ?";

這是默認查詢,它通過JdbcDaoImpl的userName加載用戶的所有權限。 因此,如果您仍然想使用默認的JdbcDaoImpl您可以設置自定義查詢,該查詢將對您的表執行此操作,並將其作為參數。

我不確定users表的模式是什么,但是類似的東西應該是相似的(如果您以編程方式配置JdbcDaoImpl bean):

String query = "select username,authority " +
        "from authorities join users on users.id = authorities.user_id " +
        "where users.username = ?";
jdbcDaoImpl.setAuthoritiesByUsernameQuery(query);

或者,如果您從XML創建JdbcDaoImpl:

<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <property name="authoritiesByUsernameQuery"
              value="select username,authority from authorities
                        join users on users.id = authorities.user_id
                        where users.username = ?"/>
</bean>

您可能需要更改其他一些默認查詢以適合您的模式,請在JdbcDaoImpl中對其進行查看。

如果與默認的JdbcDaoImpl相距太遠,您可能還考慮編寫自己的UserDetailsService實現的可能性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM