找不到 Spring Boot OAuth 2.0 UserDetails 用户 [英] Spring Boot OAuth 2.0 UserDetails user not found

查看:70
本文介绍了找不到 Spring Boot OAuth 2.0 UserDetails 用户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to Spring Boot, and I am trying to configure OAuth 2.0. The problem I am having at this moment is that I keep getting the following message when I attempt to request for an access token:

{错误":invalid_grant","error_description": "错误的凭据"}

{ "error": "invalid_grant", "error_description": "Bad credentials" }

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

The error message in the Spring Boot console says that the user cannot be found.

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

: Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider : User 'stromero' not found : Returning cached instance of singleton bean 'authenticationAuditListener'

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

I have implemented a custom user that has already been saved to a database using JPA, I am unable to figure why Spring Security cannot find this user, it may an issue with my logic or configuration. If someone with more experience can look at my code and perhaps guide me to the right direction, that would be greatly appreciated.

这是 HTTP 请求:

This is the HTTP Request:

POST/oauth/token HTTP/1.1主机:本地主机:8181授权:基本 YnJvd3NlcjpzZWNyZXQ=缓存控制:无缓存内容类型:应用程序/x-www-form-urlencoded用户名=stromero&password=password&client_id=browser&client_secret=secret&grant_type=password

POST /oauth/token HTTP/1.1 Host: localhost:8181 Authorization: Basic YnJvd3NlcjpzZWNyZXQ= Cache-Control: no-cache Content-Type: application/x-www-form-urlencoded username=stromero&password=password&client_id=browser&client_secret=secret&grant_type=password

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

These are the classes that I used to implement my custom user and OAuth 2.0

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

public CustomUser findByUsername(String name);
}

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

Below is the custom user I have created

@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对象返回

Below is a customdetails service that reads the user information from the database and returns it as a UserDetails Object

@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 的数据结构

The class below is a data structure that holds both the UserDetailsService and ClientDetailsService

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 的配置

The class below is my configuration for OAuth 2.0 using Spring Boot

 @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 文件

Below is my pom.xml file

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

推荐答案

是的,我遇到了同样的问题...想使用 JPA 的 UserDetailsS​​ervice 但同样的问题 - 找不到用户... 最终得到解决,感谢 Dave Syer 在 GitHub 上的 OAuth2 示例.

Yeah, I had the same issue... wanted to use JPA's UserDetailsService but the same problem - user couldn't be found... got resolved it eventually, thanks to Dave Syer's OAuth2 samples on GitHub.

问题似乎出在 @EnableAuthorizationServer AuthorizationServer 类中自动装配的 authenticationManager 实例中.AuthenticationManager 在那里自动装配并且似乎使用默认的 DAOAuthenticationProvider 进行初始化,并且由于某种原因它不使用自定义 JPA UserDetailsS​​ervice 我们在 WebSecurityConfiguration 中初始化 authenticationManager>.

The problem seem to be in authenticationManager instance autowired in @EnableAuthorizationServer AuthorizationServer class. AuthenticationManager is autowired there and seems to initialize with default DAOAuthenticationProvider, and for some reason it doesn't use custom JPA UserDetailsService we initialize authenticationManager with in WebSecurityConfiguration.

在 Dave Syer 示例中,authenticationManager 在 WebSecurityConfiguration 中作为 bean 公开:

In Dave Syer samples authenticationManager is exposed as a bean in WebSecurityConfiguration:

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

然后在 AuthorizationServer 中我们自动装配 authenticationManager 如下:

then in AuthorizationServer we autowire authenticationManager as follows:

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

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

Once I did it I finally managed to get my user authenticated against my customer JPA user repository.

这篇关于找不到 Spring Boot OAuth 2.0 UserDetails 用户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆