首页 > 解决方案 > 来自数据库的 Spring Boot Oauth2 UserDetailsS​​ervice - 访问被拒绝

问题描述

我一直在尝试实现 Oauth2 授权和资源服务器。到目前为止,我一直在使用硬编码用户:

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public UserDetailsService userDetailsService() {

        UserDetails user=User.builder()
            .username("user")
            .password( passwordEncoder().encode("secret") )
            .roles("USER")
            .build();

        return new InMemoryUserDetailsManager(user);
    }

这效果很好。但是我的数据库中有多个用户,我想将它们用作用户登录。

因此,我从该类中删除了上述 @Bean 方法,并将 UserDetailsS​​ervice 实现为它自己的类:

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) {
        User user = userRepository.findByUsername(username);
        System.out.println("loadUserByUsername: "+user);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }
        return new MyUserPrincipal(user);
    }
}

还有我的 UserDetails 实现:

public class MyUserPrincipal implements UserDetails {

    private static final long serialVersionUID = -1480402973442569981L;
    private User user;

    public MyUserPrincipal(User user) {
        this.user = user;
    }

    @Override
    public String getUsername() {
        System.out.println("Getting username: "+user.getUsername());
        return user.getUsername();
    }

    @Override
    public String getPassword() {
        System.out.println("Getting password: "+user.getPassword());
        return user.getPassword();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        final List<GrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("USER"));
        return authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    public User getUser() {
        return user;
    }

}

我的用户表中有以下内容:

mysql> select * from user;
+----+--------------------------------------------------------------+----------+
| id | password                                                     | username |
+----+--------------------------------------------------------------+----------+
|  1 | $2a$10$7tYTQ/dMXASLZG2OptweV.JdVH9RoDsG2ighxq5im3A/srnOo9OYC | user     |
+----+--------------------------------------------------------------+----------+
1 row in set (0.00 sec)

使用这个新设置,我可以像以前一样检索我的访问令牌:

发布 /oauth/令牌

{
    "access_token": "8cf0a509-2a56-4adc-ace7-38f39beee8a1",
    "token_type": "bearer",
    "refresh_token": "742a109f-6768-48b5-9818-76397dc658fb",
    "expires_in": 42705,
    "scope": "read write"
}

但是,当我像以前一样尝试访问资源时,它现在给了我以下响应:

获取/资金

{
    "error": "access_denied",
    "error_description": "Access is denied"
}

我没有看到任何错误或异常抛出。我怀疑这与角色有关,而这个用户只是没有被授权。这是我的 ClientDetailsS​​erviceConfigurer 设置:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    //...

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.inMemory()
            .withClient("cliente")
            .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
            .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT", "USER")
            .scopes("read", "write")
            .autoApprove(true)
            .secret(passwordEncoder().encode("password"));

    }

更新

这是我的 ResourceServerConfigurerAdapter 实现:

@Configuration
@EnableWebSecurity
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
{
    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.anonymous().disable()
            .requestMatchers()
                .antMatchers("/funds/**")
            .and().authorizeRequests()
                .antMatchers("/funds/**")
                .access("hasRole('USER')")
            .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }   

}

标签: spring-bootspring-securityspring-oauth2

解决方案


我猜在您的 ClientDetailsS​​erviceConfigurer 设置中,您需要将用户角色提供为“ROLE_USER”而不是“USER”。因为在内部(在用户中)所有角色都以前缀ROLE_保存。

在用户类中(添加了后缀):

authorities.add(new SimpleGrantedAuthority("ROLE_" + role));

推荐阅读