带有自定义 UserDetailsS​​ervice 的 Spring Boot

Posted

技术标签:

【中文标题】带有自定义 UserDetailsS​​ervice 的 Spring Boot【英文标题】:Spring Boot with custom UserDetailsService 【发布时间】:2014-09-03 13:58:53 【问题描述】:

将我的 UserDetailsS​​ervice(使用 Spring Data JPA)的自定义实现添加到 Spring Boot 应用程序的正确方法是什么?

public class DatabaseUserDetailsService implements UserDetailsService 

    @Inject
    private UserAccountService userAccountService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
        User user = userAccountService.getUserByEmail(username);
        return new MyUserDetails(user);
    




public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> 

    public User findByEmail(String email);





@Service
public class UserAccountService 

    @Inject
    protected UserRepository userRepository;

    public User getUserByEmail(String email) 
        return userRepository.findByEmail(email);
    




@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.sample")
@EntityScan(basePackages =  "com.sample" )
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class Application 

    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    

    ...

    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
    protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter 

        @Override
        protected void configure(HttpSecurity http) throws Exception 
            http
                .authorizeRequests()
                    .antMatchers("/").hasRole("USER")
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll();
        


    

    @Order(Ordered.HIGHEST_PRECEDENCE + 10)
    protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter 

        @Inject
        private UserAccountService userAccountService;

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception 
            auth.userDetailsService(userDetailsService());
        

        @Bean
        public UserDetailsService userDetailsService() 
            return new DatabaseUserDetailsService();
        

    




@Entity
public class User extends AbstractPersistable<Long> 

    @ManyToMany
    private List<Role> roles = new ArrayList<Role>();

    // getter, setter




@Entity
public class Role extends AbstractPersistable<Long> 

    @Column(nullable = false)
    private String authority;

    // getter, setter


我无法启动应用程序,因为我得到了(这里是完全例外http://pastebin.com/gM804mvQ)

Caused by: org.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: com.sample.model.User.roles[com.sample.model.Role]
    at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1134)

当我用auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("...).authoritiesByUsernameQuery("...") 配置我的ApplicationSecurity 时,一切正常,包括JPA 和Spring Data 存储库。

【问题讨论】:

问题在于 JPA 映射。请添加用户和角色实体(类)。 已添加实体。无论如何,我认为实体没有问题,因为没有我的 UserDetailsS​​ervice,JPA 可以正常工作。 不过我认为 Evgeni 是对的。该错误是映射错误。也许你可以分享一个完整的项目? @DaveSyer,我在这里尝试将其最小化github.com/igo/spring-boot-userdetails。仍然无法运行,但是我遇到了另一个异常 NPE - DatabaseUserDetailsS​​ervice 中的 UserAccountService 为空。请尝试,您可能知道如何使用自定义 UserDetailsS​​ervice :) 您的应用似乎对我有用(一旦我将 @Configuration 添加到 AuthenticationSecurity)。我该如何打破它? 【参考方案1】:

您的应用似乎对我有用(一旦我将@Configuration 添加到AuthenticationSecurity)。这是另一个使用 JPA UserDetailsService 的简单应用程序的工作示例,以防万一:https://github.com/scratches/jpa-method-security-sample

【讨论】:

谢谢,这有助于前进。但现在我得到o.s.s.w.a.www.BasicAuthenticationFilter : Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException: failed to lazily initialize a collection of role: com.sample.model.User.roles, could not initialize proxy - no Session。然而,我没有找到任何加载延迟获取角色的示例。我更新了我的 github 示例。 懒惰的角色听起来是个坏主意(您总是需要在身份验证后检查授权),但这看起来就像您没有交易一样。也许UserDetailsService 疖子是事务性的加载角色,用一块石头杀死两只鸟,就像它一样? @DaveSyer 你好,我不明白你的意思。我和 OP (failed to lazily initialize a collection of role) 有同样的错误。我是否必须将fetch=FetchType.EAGER 添加到com.sample.model.User.roles 或者是否有不那么繁重的方法?谢谢! 理想情况下,您不应将 JPA 用于用户详细信息。如果您必须然后获取UserDetailsService 中的角色(并使其具有事务性)。【参考方案2】:

您也可以关注this blog实现自定义用户详情服务。

这个例子展示了如何将 bean 发送到 userdetails 服务进行注入。

    在 WebSecurityConfigurer 中自动装配存储库 通过参数化构造函数将此 bean 作为参数发送到用户详细信息服务。 为此分配一个私有成员并用于从数据库加载用户。

【讨论】:

以上是关于带有自定义 UserDetailsS​​ervice 的 Spring Boot的主要内容,如果未能解决你的问题,请参考以下文章

Spring security 3.2:自定义 UserDetails 和 UserDetailsS​​ervice 是不是需要自定义 AuthenticationManager?

Spring Security 自定义 UserDetailsS​​ervice 和自定义 User 类

在自定义 UserDetailsS​​ervice 中访问当前 ClientDetails

Spring Security Java Config - 自定义 AuthenticationProvider 和 UserDetailsS​​ervice

使用我的自定义 UserDetailsS​​ervice 后,httpsession 生命周期事件不起作用

Spring Security:来自 UserDetailsS​​ervice 的自定义异常消息