使用Spring OAuth2 Jdbc令牌存储时无法填充User对象

时间:2015-06-04 17:30:51

标签: spring-security spring-security-oauth2

我使用基于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。

CustomUserDetailsS​​ervice

@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;
    }
}

2 个答案:

答案 0 :(得分:2)

问题在于&#34; UserRepositoryUserDetails&#34;你正在创建的是不可序列化的。

UserRepositoryUserDetails正在实施&#34; UserDetails&#34;这是Serializable但它正在扩展的类#34; User&#34;不可序列化。

您必须从comiler收到警告以添加serialId。

解决方案

使您的UserRepositoryUserDetails可序列化。

答案 1 :(得分:0)

用户类可序列化之后,一切都按预期工作。