一尘不染

找不到Spring Boot OAuth 2.0 UserDetails用户

spring-boot

我是Spring Boot的新手,并且正在尝试配置OAuth 2.0。我目前遇到的问题是,当我尝试请求访问令牌时,我不断收到以下消息:

{“ error”:“ invalid_grant”,“ error_description”:“不良凭证”}

Spring Boot控制台中的错误消息说找不到用户。

:使用org.springframework.security.authentication.dao.DaoAuthenticationProvider进行身份验证尝试:未找到用户“
stromero”:返回单例bean“ authenticationAuditListener”的缓存实例

我实现了一个自定义用户,该用户已经使用JPA保存到数据库中,我无法弄清楚为什么Spring
Security无法找到该用户,这可能是我的逻辑或配置出现问题。如果有更多经验的人可以看一下我的代码,也许可以指导我朝正确的方向发展,那将不胜感激。

这是HTTP请求:

POST / oauth / token HTTP / 1.1主机:localhost:8181授权:基本YnJvd3NlcjpzZWNyZXQ
=缓存控制:无缓存内容类型:application / x-www-form-urlencoded username =
stromero&password = password&client_id = browser&client_secret =
secret&grant_type =

这些是我用来实现自定义用户和OAuth 2.0的类

@Repository
public interface UserRepository extends CrudRepository<CustomUser, String> {

public CustomUser findByUsername(String name);
}

以下是我创建的自定义用户

@Entity
@Table (name = "custom_user")
 public class CustomUser {

@Id
@Column(name = "id", nullable = false, updatable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "username", unique=true, nullable = false)
private String username;
@Column(name = "password", nullable = false)
private String password;
@ElementCollection
private List<String> roles = new ArrayList<>();

public List<String> getRoles() {
    return roles;
}

public void setRoles(List<String> roles) {
    this.roles = roles;
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}
}

下面是一个customdetails服务,该服务从数据库中读取用户信息并将其作为UserDetails对象返回

@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {

@Autowired
private UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

    CustomUser customUser = userRepository.findByUsername(s);

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    return new User(
            customUser .getUsername(),
            customUser .getPassword().toLowerCase(),
            enabled,
            accountNonExpired,
            credentialsNonExpired,
            accountNonLocked,
            getAuthorities(customUser.getRoles()));
}
public Collection<? extends GrantedAuthority> getAuthorities(List<String> roles) {
    List<GrantedAuthority> authList = getGrantedAuthorities(roles);
    return authList;
}


public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    for (String role : roles) {
        authorities.add(new SimpleGrantedAuthority(role));
    }
    return authorities;
}
}

下面的类是一个数据结构,同时包含UserDetailsS​​ervice和ClientDetailsS​​ervice

public class ClientAndUserDetailsService implements UserDetailsService,
    ClientDetailsService {

    private final ClientDetailsService clients;

    private final UserDetailsService users;

    private final ClientDetailsUserDetailsService clientDetailsWrapper;

    public ClientAndUserDetailsService(ClientDetailsService clients,
                                       UserDetailsService users) {
        super();
        this.clients = clients;
        this.users = users;
        clientDetailsWrapper = new ClientDetailsUserDetailsService(this.clients);
    }

    @Override
    public ClientDetails loadClientByClientId(String clientId)
            throws ClientRegistrationException {
        return clients.loadClientByClientId(clientId);
    }

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        UserDetails user = null;
        try{
            user = users.loadUserByUsername(username);
        }catch(UsernameNotFoundException e){
            user = clientDetailsWrapper.loadUserByUsername(username);
        }
        return user;
    }
    }

下面的类是我使用Spring Boot对OAuth 2.0的配置

 @Configuration
public class OAuth2SecurityConfiguration {

@Configuration
@EnableWebSecurity
protected static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    protected void registerAuthentication(
            final AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }
}


@Configuration
@EnableResourceServer
protected static class ResourceServer extends
        ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.csrf().disable();

        http.authorizeRequests().antMatchers("/oauth/token").anonymous();

        // Require all GET requests to have client "read" scope
        http.authorizeRequests().antMatchers(HttpMethod.GET, "/**")
                .access("#oauth2.hasScope('read')");

        // Require all POST requests to have client "write" scope
        http.authorizeRequests().antMatchers(HttpMethod.POST,"/**")
                .access("#oauth2.hasScope('write')");
    }

}

@Configuration
@EnableAuthorizationServer
@Order(Ordered.LOWEST_PRECEDENCE - 100)
protected static class AuthorizationServer extends
        AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    private ClientAndUserDetailsService combinedService;

    public AuthorizationServer() throws Exception {

        ClientDetailsService clientDetailsService = new InMemoryClientDetailsServiceBuilder()
                .withClient("browser")
                .secret("secret")
                .authorizedGrantTypes("password")
                .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
                .scopes("read","write")
                .resourceIds("message")
                .accessTokenValiditySeconds(7200)
                .and()
                .build();

        // Create a series of hard-coded users.
        UserDetailsService userDetailsService = new CustomUserDetailsService();
        combinedService = new ClientAndUserDetailsService(clientDetailsService,   userDetailsService);
    }

    @Bean
    public ClientDetailsService clientDetailsService() throws Exception {
        return combinedService;
    }
    @Bean
    public UserDetailsService userDetailsService() {
        return combinedService;
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients)
            throws Exception {
        clients.withClientDetails(clientDetailsService());
    }

}

}

下面是我的pom.xml文件

    <properties>
    <tomcat.version>8.0.8</tomcat.version>
</properties>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <!-- Postgres JDBC Driver -->

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.2-1002-jdbc4</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- Hibernate validator -->

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>


    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>17.0</version>
    </dependency>

</dependencies>

阅读 268

收藏
2020-05-30

共1个答案

一尘不染

是的,我遇到了同样的问题…想要使用JPA,UserDetailsService但是同样的问题-
找不到用户…最终得到了解决,这要归功于GitHub上Dave Syer的OAuth2示例。

问题似乎出在@EnableAuthorizationServer AuthorizationServer类自动连接的authenticationManager实例中。AuthenticationManager是自动连接的,似乎使用默认值初始化DAOAuthenticationProvider,由于某种原因,它不使用自定义JPA,因此UserDetailsService我们使用in初始化了authenticationManager
WebSecurityConfiguration

在Dave Syer样本中,authenticationManager在Bean中公开为WebSecurityConfiguration

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

然后在AuthorizationServer我们自动连接authenticationManager,如下所示:

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

完成之后,我最终设法根据我的客户JPA用户存储库对我的用户进行身份验证。

2020-05-30