带有自定义 UserDetailsService 的 Spring Boot
Posted
技术标签:
【中文标题】带有自定义 UserDetailsService 的 Spring Boot【英文标题】:Spring Boot with custom UserDetailsService 【发布时间】:2014-09-03 13:58:53 【问题描述】:将我的 UserDetailsService(使用 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 映射。请添加用户和角色实体(类)。 已添加实体。无论如何,我认为实体没有问题,因为没有我的 UserDetailsService,JPA 可以正常工作。 不过我认为 Evgeni 是对的。该错误是映射错误。也许你可以分享一个完整的项目? @DaveSyer,我在这里尝试将其最小化github.com/igo/spring-boot-userdetails。仍然无法运行,但是我遇到了另一个异常 NPE - DatabaseUserDetailsService 中的 UserAccountService 为空。请尝试,您可能知道如何使用自定义 UserDetailsService :) 您的应用似乎对我有用(一旦我将 @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 作为参数发送到用户详细信息服务。
为此分配一个私有成员并用于从数据库加载用户。
【讨论】:
以上是关于带有自定义 UserDetailsService 的 Spring Boot的主要内容,如果未能解决你的问题,请参考以下文章
Spring security 3.2:自定义 UserDetails 和 UserDetailsService 是不是需要自定义 AuthenticationManager?
Spring Security 自定义 UserDetailsService 和自定义 User 类
在自定义 UserDetailsService 中访问当前 ClientDetails
Spring Security Java Config - 自定义 AuthenticationProvider 和 UserDetailsService