Spring 从数据库启动 Oauth2 UserDetailsService - 访问被拒绝
Spring Boot Oauth2 UserDetailsService from database - access denied
我一直在尝试实现 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);
}
效果很好。但是我的数据库中有多个用户,我想将其用作用户登录。
因此,我从 class 中删除了上述 @Bean 方法,并将 UserDetailsService 实现为它自己的 class:
@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;
}
}
我的用户 table:
mysql> select * from user;
+----+--------------------------------------------------------------+----------+
| id | password | username |
+----+--------------------------------------------------------------+----------+
| 1 | atYTQ/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"
}
我没有看到任何错误或异常抛出。我怀疑这与角色有关,而这个用户只是没有被授权。这是我的 ClientDetailsServiceConfigurer 设置:
@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());
}
}
我想在您的 ClientDetailsServiceConfigurer 设置中,您需要提供 "ROLE_USER" 而不是 "USER" 的用户角色。
因为在内部(在用户中)所有角色都保存有前缀 ROLE_.
在用户class中(后缀已加):
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
Spring 安全性会自动为任何角色添加前缀 ROLE_
。这些更改是 SEC-2758
的一部分
由于 SimpleGrantedAuthority 是权限,而不是角色,我们需要明确添加 ROLE_
前缀以使其成为角色。
以下代码需要更新为 ROLE_
前缀:
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
final List<GrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
return authorities;
}
我一直在尝试实现 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);
}
效果很好。但是我的数据库中有多个用户,我想将其用作用户登录。
因此,我从 class 中删除了上述 @Bean 方法,并将 UserDetailsService 实现为它自己的 class:
@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;
}
}
我的用户 table:
mysql> select * from user;
+----+--------------------------------------------------------------+----------+
| id | password | username |
+----+--------------------------------------------------------------+----------+
| 1 | atYTQ/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"
}
我没有看到任何错误或异常抛出。我怀疑这与角色有关,而这个用户只是没有被授权。这是我的 ClientDetailsServiceConfigurer 设置:
@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());
}
}
我想在您的 ClientDetailsServiceConfigurer 设置中,您需要提供 "ROLE_USER" 而不是 "USER" 的用户角色。 因为在内部(在用户中)所有角色都保存有前缀 ROLE_.
在用户class中(后缀已加):
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
Spring 安全性会自动为任何角色添加前缀 ROLE_
。这些更改是 SEC-2758
由于 SimpleGrantedAuthority 是权限,而不是角色,我们需要明确添加 ROLE_
前缀以使其成为角色。
以下代码需要更新为 ROLE_
前缀:
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
final List<GrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
return authorities;
}