我使用基于Jdbc的令牌存储更新了Roy Clarkson的Spring REST服务(https://github.com/royclarkson/spring-rest-service-oauth)。原始实现使用内存中的令牌存储。我能够在User对象中看到用户详细信息。另一方面,在切换到基于Jdbc的令牌存储之后,User对象中的所有字段都是空的。当我使用基于Jdbc的令牌存储时,Spring安全性似乎无法将访问令牌与我获取令牌的用户相关联。
内存中令牌存储实现:
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
private TokenStore tokenStore = new InMemoryTokenStore();
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private ClientDetailsService clientDetailsService;
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// @formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// @formatter:on
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.withClientDetails(clientDetailsService);
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
REST端点:
@RequestMapping("/greeting")
public Greeting greeting(@AuthenticationPrincipal User user) {
return new Greeting(counter.incrementAndGet(), String.format(template, user.getName()));
}
user.getName()返回获取访问令牌的用户的名称。
jdbc令牌存储实现:
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private TokenStore tokenStore;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private ClientDetailsService clientDetailsService;
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// @formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// @formatter:on
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.withClientDetails(clientDetailsService);
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
REST端点:
@RequestMapping("/greeting")
public Greeting greeting(@AuthenticationPrincipal User user) {
return new Greeting(counter.incrementAndGet(), String.format(template, user.getName()));
}
user.getName()返回null。
CustomUserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByLogin(username);
if (user == null) {
throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
}
return new UserRepositoryUserDetails(user);
}
private final static class UserRepositoryUserDetails extends User implements UserDetails {
private static final long serialVersionUID = 1L;
private UserRepositoryUserDetails(User user) {
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles();
}
@Override
public String getUsername() {
return getLogin();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
}
用户
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@NotEmpty
private String name;
@NotEmpty
@Column(unique = true, nullable = false)
private String login;
@NotEmpty
private String password;
@NotEmpty
private String privilege;
@JsonIgnore
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") })
private Set<Role> roles = new HashSet<Role>();
public User() {
}
public User(User user) {
super();
this.id = user.getId();
this.name = user.getName();
this.login = user.getLogin();
this.password = user.getPassword();
this.roles = user.getRoles();
this.privilege = user.getPrivilege();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPrivilege() {return privilege; }
public void setPrivilege(String privilege) {this.privilege = privilege; }
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
答案 0 :(得分:2)
问题在于&#34; UserRepositoryUserDetails&#34;你正在创建的是不可序列化的。
UserRepositoryUserDetails正在实施&#34; UserDetails&#34;这是Serializable但它正在扩展的类#34; User&#34;不可序列化。
您必须从comiler收到警告以添加serialId。
解决方案
使您的UserRepositoryUserDetails可序列化。
答案 1 :(得分:0)
在用户类可序列化之后,一切都按预期工作。