简体   繁体   English

Spring Security OAuth2中注入自定义userDetailsS​​ervice的问题

[英]problems injecting custom userDetailsService in Spring Security OAuth2

I am using Spring Security OAuth2 2.0.7.RELEASE. 我正在使用Spring Security OAuth2 2.0.7.RELEASE。 As i am using ORM to connect to my database and default JdbcUserDetailsManager uses jdbc i wanted to implement my own UserDetailsService, which is 当我使用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;
    }
}

Besides, i've modified authorities schema as follows: 此外,我还修改了权限架构,如下所示:

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    |                |
+--------------+---------------------+------+-----+---------+----------------+

Then i am injecting my custom userDetailsService like this: 然后,我像这样注入我的自定义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
    }
}

If i send /oauth/token request with grant_type=password then i get this error 如果我使用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

(where clientId and clientSecret is encoded) (其中对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'"
}

Apparently is still using the default JdbcDaoImpl. 显然仍在使用默认的JdbcDaoImpl。 In fact, when i started debugging, i found that is following these steps: 实际上,当我开始调试时,发现执行以下步骤:

  1. Authenticates client (OK, since i haven't modified oauth_client_details table) 对客户端进行身份验证(好的,因为我还没有修改oauth_client_details表)
  2. Authenticates user with my custom userDetailsService(OK, users table modificated but my custom userDetailsService supports changes) 使用我的自定义userDetailsS​​ervice对用户进行身份验证(好的,已修改users表,但我的自定义userDetailsS​​ervice支持更改)
  3. Authenticates user with default userDetailsService(ERROR) 使用默认的userDetailsS​​ervice(ERROR)对用户进行身份验证

I don't know why this is happening. 我不知道为什么会这样。 It sounds like a bug to me. 对我来说,这听起来像个虫子。 Do you find anything wrong? 你有没有发现什么问题?

You are using auth.jdbcAuthentication().dataSource(this.dataSource).and().userDetailsService(‌​this.userService);// Inject custom and I here it's creating two auth managers - one with default JdbcDaoImpl and dataSource pointing to this.dataSource and another with your custom userService . 您正在使用auth.jdbcAuthentication().dataSource(this.dataSource).and().userDetailsService(‌​this.userService);// Inject custom ,我在这里创建了两个auth管理器-一个具有默认的JdbcDaoImpldataSource指向this.dataSource和另一个带有自定义userService Try just putting auth.userDetailsService(this.userService) (I hope that userService already have jdbc autowired inside). 尝试仅将auth.userDetailsService(this.userService) (我希望userService已将jdbc自动连接到其中)。

The point here is that .and() is used to add different authentication configurations to the authentication manager, not configuring the jdbcAuthentication() one. 这里的重点是.and()用于向身份验证管理器添加不同的身份验证配置,而不是配置jdbcAuthentication()

In 2.0.7 when you do a POST/GET request on /oauth/token with grant type as password , it will actually except a ClientDetailsUserDetailsService but not UserDetailsService . 2.0.7当您以授予类型作为password/oauth/token进行POST/GET请求时,它实际上将是ClientDetailsUserDetailsService而不是UserDetailsService

I had similar issue and this is how I solved it : 我有类似的问题,这就是我解决的方法:

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>

authenticationManager is the bean for AppClientDetailsUserDetailsService whose constructor argument is AppConsumerDetailsService . authenticationManagerAppClientDetailsUserDetailsService的bean,其构造函数参数为AppConsumerDetailsService

The problem is that you are using default JdbcDaoImpl . 问题是您正在使用默认的JdbcDaoImpl The query which is causing the problem is 引起问题的查询是

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

This is used as a default query to load all authorities for the user by userName inside JdbcDaoImpl . 这是默认查询,它通过JdbcDaoImpl的userName加载用户的所有权限。 So if you still want to use default JdbcDaoImpl - you can set the custom query, which will do the job with your tables, as the parameter of it. 因此,如果您仍然想使用默认的JdbcDaoImpl您可以设置自定义查询,该查询将对您的表执行此操作,并将其作为参数。

I'm not sure what is the schema of you users table, but something like this should be similar(if you are configuring JdbcDaoImpl bean programmatically): 我不确定users表的模式是什么,但是类似的东西应该是相似的(如果您以编程方式配置JdbcDaoImpl bean):

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

Or if you create JdbcDaoImpl from XML: 或者,如果您从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>

There might be some other default queries that you would like to change to fit your schema, take a look at them inside JdbcDaoImpl . 您可能需要更改其他一些默认查询以适合您的模式,请在JdbcDaoImpl中对其进行查看。

You might also consider a possibility of writing your own implementation of UserDetailsService if it will start getting too far from default JdbcDaoImpl one. 如果与默认的JdbcDaoImpl相距太远,您可能还考虑编写自己的UserDetailsService实现的可能性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring 安全 OAuth2 刷新令牌 - IllegalStateException,需要 UserDetailsS​​ervice - Spring security OAuth2 Refresh Token - IllegalStateException, UserDetailsService is required Spring Boot OAuth2具有基本身份验证和自定义UserDetailsS​​ervice - Spring Boot OAuth2 with basic authentication and custom UserDetailsService Spring Security Oauth - 永远不会调用自定义UserDetailsS​​ervice - Spring Security Oauth - Custom UserDetailsService is never getting called Spring Boot 2.3 和 Spring 安全性 5 - 在一个模式中支持 UserDetailsService 和 OAuth2 - Spring Boot 2.3 and Spring Security 5 - Support UserDetailsService and OAuth2 in one schema Spring Boot OAuth2带有自定义安全过滤器 - Spring Boot OAuth2 with custom security filter 使用 spring security 和 oauth2 刷新令牌调用失败,错误:需要 UserDetailsS​​ervice - Refresh token call fails using spring security an oauth2 with error: UserDetailsService is required Spring Security OAuth2 自定义成功用户 - Spring Security OAuth2 custom success user Spring Security自定义UserDetailsS​​ervice和自定义User类 - Spring Security custom UserDetailsService and custom User class @EJB注入到Custom UserdetailsS​​ervice中(实现Spring Security UserDetailsS​​ervice) - @EJB injection in a Custom UserdetailsService (implementing Spring Security UserDetailsService) Spring Security自定义身份验证 - AuthenticationProvider与UserDetailsS​​ervice - Spring Security Custom Authentication - AuthenticationProvider vs UserDetailsService
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM