当前位置:  开发笔记 > 编程语言 > 正文

未找到Spring Boot OAuth 2.0 UserDetails用户

如何解决《未找到SpringBootOAuth2.0UserDetails用户》经验,为你挑选了1个好方法。

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

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

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

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

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

这是HTTP请求:

POST /的OAuth /令牌HTTP/1.1主机:本地主机:8181授权:基本YnJvd3NlcjpzZWNyZXQ =缓存控制:无缓存内容类型:应用程序/ x-WWW窗体-urlencoded用户名= stromero和密码=密码&CLIENT_ID =浏览器&client_secret =秘密&grant_type =密码

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

@Repository
public interface UserRepository extends CrudRepository {

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 roles = new ArrayList<>();

public List getRoles() {
    return roles;
}

public void setRoles(List 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 getAuthorities(List roles) {
    List authList = getGrantedAuthorities(roles);
    return authList;
}


public static List getGrantedAuthorities(List roles) {
    List authorities = new ArrayList();
    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文件

    
    8.0.8




    
        org.springframework.boot
        spring-boot-starter-web
    

    
        org.springframework.boot
        spring-boot-starter-logging
    

    
        org.springframework.boot
        spring-boot-starter-actuator
    

    
        org.springframework.boot
        spring-boot-starter-test
    

    

    
        org.postgresql
        postgresql
        9.2-1002-jdbc4
    

    
        org.springframework.boot
        spring-boot-starter-jdbc
    

    
        org.springframework.boot
        spring-boot-starter-data-jpa
    

    

    
        org.springframework.boot
        spring-boot-starter-security
    


    
        org.springframework.security.oauth
        spring-security-oauth2
        2.0.3.RELEASE
    

    
        com.google.guava
        guava
        17.0
    


小智.. 17

是的,我有同样的问题...想要使用JPA UserDetailsService但是同样的问题 - 用户无法找到...最终得到了解决,感谢Dave Syer在GitHub上的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我们autowire authenticationManager中如下:

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

一旦我这样做了,我终于设法让我的用户通过我的客户JPA用户存储库进行身份验证.



1> 小智..:

是的,我有同样的问题...想要使用JPA UserDetailsService但是同样的问题 - 用户无法找到...最终得到了解决,感谢Dave Syer在GitHub上的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我们autowire authenticationManager中如下:

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

一旦我这样做了,我终于设法让我的用户通过我的客户JPA用户存储库进行身份验证.

推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有