我一直在尝试实现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方法,并将UserDetailsService实现为自己的类:
@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 /令牌
{
"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"));
}
我想在ClientDetailsServiceConfigurer设置中,您需要提供用户角色为“ ROLE_USER”,而不是“ USER”。因为在内部(用户中),所有角色均以前缀ROLE _。]保存。
在用户类中(添加了后缀):
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
Spring Security会自动为任何角色加上ROLE_
前缀。所做的更改是SEC-2758