Spring 安全扩展来自其他 jar 的配置
Spring Security extend configuration from other jar
我有一个应用程序依赖于定义了安全性的地方。典型配置:
@Configuration
@EnableWebSecurity
public class AuthConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(DEFAULT_PERMIT_ALL_PATHS).permitAll()
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling()
.and()
.csrf().disable().httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
User.UserBuilder users = User.withDefaultPasswordEncoder();
authManagerBuilder.inMemoryAuthentication().withUser(users.username("FOO").password("BAR").roles("USER").build());
}
}
以上是第一个项目。我有第二个项目,我对上面的项目有 POM 依赖。现在我想添加一个额外的用户,但我必须在我的第二个项目中执行此操作,该项目仅依赖于第一个具有安全性的项目。
我可以复制并粘贴整个 AuthConfiguration,然后我有 2 个安全过滤器链,但这是个坏主意。该应用程序开始处理请求,查看目标 URI 是什么。两个过滤器链具有相同的 antMatchers(我只想添加额外的用户)并且只有一个过滤器链正在处理。因此,它部分起作用 - 来自第一个或第二个项目的用户起作用(它取决于 AuthConfiguration 的 @Order)。
也许可以在我的第二个项目中注入例如 AuthenticationManagerBuilder 和 extend/add 其他用户?我试过了,但没有用。我在第二个项目中添加了这样的代码:
@Configuration
public class AdditionalUsersConfiguration() {
public AdditionalUsersConfiguration(AuthenticationManagerBuilder builder) throws Exception {
User.UserBuilder users = User.withDefaultPasswordEncoder();
authManagerBuilder.inMemoryAuthentication()
.withUser(users.username("FOO").password("BAR").roles("USER")
.withUser(users.username("FOO2").password("BAR").roles("USER").build());
}
}
只有第一个用户 FOO 有效,看起来它来自定义它的第一个项目。
编辑:我也试过这个问题的方法 How can I add users to the inMemoryAuthentication builder after it has been built?
我在我的第二个项目中添加了这段代码:
@Configuration
public class NextApproachConfiguration() {
public NextApproachConfiguration(InMemoryUserDetailsManager manager) throws Exception {
manager.createUser(new User("FOO2", "BAR", new ArrayList<GrantedAuthority>()));
// in debugger here I see two users [FOO, FOO2]
}
}
看起来不错。在调试器(代码注释)中,我看到了来自第一个项目的用户和新用户。但是当我用邮递员请求端点时,我在调试器内部看到它如何调用 InMemoryUserDetailsManager::loadByUsername() 并且这个管理器的实例与我添加用户二的实例不同。而且它只有第一个项目的一个用户。
当我使用 debbuger 启动应用程序时,我看到首先在我添加第二个用户的地方执行上面的代码,然后从第一个项目 (AuthConfiguration class) 执行代码,其中 AuthenticationManagerBuilder::inMemoryAuthentication 转到 InMemoryUserDetailsManagerConfigurer 并创建新的使用 new 关键字的 InMemoryUserDetailsManager 实例。
最后,在我的第二个项目中,我以这种方式从第一个项目扩展了 AuthConfiguration class:
@Configuration
@Order(90)
public class SecondProjectConfiguration extends AuthConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
super.configure(authManagerBuilder); // it creates FOO user
User.UserBuilder users = User.withDefaultPasswordEncoder();
authManagerBuilder.inMemoryAuthentication()
.withUser(users.username("FOO2").password("BAR").roles("USER").build());
}
}
并且它工作正常。 Order(90)
也是必需的,因为 AuthConfiguration 具有默认订单 100,并且它在启动时停止应用程序并出现错误。非常简单的方法,但作为最后一次尝试。
您可以采用的另一种方法是在第一个项目的配置中使用自定义 bean(例如 UserFactory),并使用它来检索所有用户并添加到内存中的用户管理器
@Autowired(required = false)
UserFactory userFactory;
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
User.UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManagerConfigurer configurer = authManagerBuilder.inMemoryAuthentication();
configurer.withUser(users.username("FOO").password("BAR").roles("USER").build());
if (userFactory != null) {
for (UserDetails userDetails: userFactory.getUsers()) {
configurer.withUser(userDetails);
}
}
}
在您的第二个项目中,您定义了 bean 并添加了额外的用户:
@Bean
public UserFactory userFactory() {
UserFactory userFactory = new UserFactory();
User.UserBuilder user = User.withDefaultPasswordEncoder();
userFactory.addUser(user.username("FOO2").password("BAR").roles("USER").build());
return userFactory;
}
如果您有许多默认用户并希望避免在扩展配置中重新键入它们,这可能更适合 class。
我有一个应用程序依赖于定义了安全性的地方。典型配置:
@Configuration
@EnableWebSecurity
public class AuthConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(DEFAULT_PERMIT_ALL_PATHS).permitAll()
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling()
.and()
.csrf().disable().httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
User.UserBuilder users = User.withDefaultPasswordEncoder();
authManagerBuilder.inMemoryAuthentication().withUser(users.username("FOO").password("BAR").roles("USER").build());
}
}
以上是第一个项目。我有第二个项目,我对上面的项目有 POM 依赖。现在我想添加一个额外的用户,但我必须在我的第二个项目中执行此操作,该项目仅依赖于第一个具有安全性的项目。
我可以复制并粘贴整个 AuthConfiguration,然后我有 2 个安全过滤器链,但这是个坏主意。该应用程序开始处理请求,查看目标 URI 是什么。两个过滤器链具有相同的 antMatchers(我只想添加额外的用户)并且只有一个过滤器链正在处理。因此,它部分起作用 - 来自第一个或第二个项目的用户起作用(它取决于 AuthConfiguration 的 @Order)。
也许可以在我的第二个项目中注入例如 AuthenticationManagerBuilder 和 extend/add 其他用户?我试过了,但没有用。我在第二个项目中添加了这样的代码:
@Configuration
public class AdditionalUsersConfiguration() {
public AdditionalUsersConfiguration(AuthenticationManagerBuilder builder) throws Exception {
User.UserBuilder users = User.withDefaultPasswordEncoder();
authManagerBuilder.inMemoryAuthentication()
.withUser(users.username("FOO").password("BAR").roles("USER")
.withUser(users.username("FOO2").password("BAR").roles("USER").build());
}
}
只有第一个用户 FOO 有效,看起来它来自定义它的第一个项目。
编辑:我也试过这个问题的方法 How can I add users to the inMemoryAuthentication builder after it has been built? 我在我的第二个项目中添加了这段代码:
@Configuration
public class NextApproachConfiguration() {
public NextApproachConfiguration(InMemoryUserDetailsManager manager) throws Exception {
manager.createUser(new User("FOO2", "BAR", new ArrayList<GrantedAuthority>()));
// in debugger here I see two users [FOO, FOO2]
}
}
看起来不错。在调试器(代码注释)中,我看到了来自第一个项目的用户和新用户。但是当我用邮递员请求端点时,我在调试器内部看到它如何调用 InMemoryUserDetailsManager::loadByUsername() 并且这个管理器的实例与我添加用户二的实例不同。而且它只有第一个项目的一个用户。 当我使用 debbuger 启动应用程序时,我看到首先在我添加第二个用户的地方执行上面的代码,然后从第一个项目 (AuthConfiguration class) 执行代码,其中 AuthenticationManagerBuilder::inMemoryAuthentication 转到 InMemoryUserDetailsManagerConfigurer 并创建新的使用 new 关键字的 InMemoryUserDetailsManager 实例。
最后,在我的第二个项目中,我以这种方式从第一个项目扩展了 AuthConfiguration class:
@Configuration
@Order(90)
public class SecondProjectConfiguration extends AuthConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
super.configure(authManagerBuilder); // it creates FOO user
User.UserBuilder users = User.withDefaultPasswordEncoder();
authManagerBuilder.inMemoryAuthentication()
.withUser(users.username("FOO2").password("BAR").roles("USER").build());
}
}
并且它工作正常。 Order(90)
也是必需的,因为 AuthConfiguration 具有默认订单 100,并且它在启动时停止应用程序并出现错误。非常简单的方法,但作为最后一次尝试。
您可以采用的另一种方法是在第一个项目的配置中使用自定义 bean(例如 UserFactory),并使用它来检索所有用户并添加到内存中的用户管理器
@Autowired(required = false)
UserFactory userFactory;
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
User.UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManagerConfigurer configurer = authManagerBuilder.inMemoryAuthentication();
configurer.withUser(users.username("FOO").password("BAR").roles("USER").build());
if (userFactory != null) {
for (UserDetails userDetails: userFactory.getUsers()) {
configurer.withUser(userDetails);
}
}
}
在您的第二个项目中,您定义了 bean 并添加了额外的用户:
@Bean
public UserFactory userFactory() {
UserFactory userFactory = new UserFactory();
User.UserBuilder user = User.withDefaultPasswordEncoder();
userFactory.addUser(user.username("FOO2").password("BAR").roles("USER").build());
return userFactory;
}
如果您有许多默认用户并希望避免在扩展配置中重新键入它们,这可能更适合 class。