【问题标题】:Spring Boot Oauth2 UserDetailsService from database - access denied来自数据库的 Spring Boot Oauth2 UserDetailsS​​ervice - 访问被拒绝
【发布时间】:2020-04-14 17:36:51
【问题描述】:

我一直在尝试实现 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)

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

POST /oauth/token

{
    "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-boot spring-security spring-oauth2


    【解决方案1】:

    Spring Security 自动为任何角色添加 ROLE_ 前缀。这些更改是作为SEC-2758的一部分进行的@

    由于 SimpleGrantedAuthority 是一个权限,而不是一个角色,我们需要显式添加 ROLE_ 前缀来使其成为角色。

    以下代码需要更新ROLE_前缀:

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 嗨。感谢您的评论。实际上,我看到的结果不一致。有时它可以工作,然后在下一个请求中我看到 access_denied。我想知道这是否与我的资源服务器有关。如果有帮助,我已经更新了我的帖子以包含我的 ResourceServerConfigurerAdapter 实现。
      猜你喜欢
      • 2017-01-31
      • 2021-02-07
      • 1970-01-01
      • 2020-12-19
      • 2020-04-26
      • 2017-10-27
      • 2014-09-03
      • 2015-04-07
      • 2015-10-19
      相关资源
      最近更新 更多