【问题标题】:spring-data-rest and spring security circular reference when using security annotations in user repository在用户存储库中使用安全注释时的 spring-data-rest 和 spring 安全循环引用
【发布时间】:2015-06-19 01:52:54
【问题描述】:

我遇到了自定义 UserDetailService 和循环引用的问题。 一旦我向我的客户存储库添加@PreAuthorize 注释,我就会收到循环引用错误。很明显,这必须发生,因为UserDetailService 也使用它。所以我的问题是如何解决循环引用?我正在使用 spring-data-rest 和 spring-security。

下面的代码应该说明重现错误所需的一切

package demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class SpringTestApplication implements CommandLineRunner{

    @Autowired
    private CustomerRepository customerRepository;

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

    @Override
    public void run(String... args) throws Exception {
        Customer admin = customerRepository.save(new Customer("Demo", "1234"));
    }
}

package demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private DemoUserDetailService demoUserDetailService;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(demoUserDetailService);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().fullyAuthenticated();
        http.httpBasic();
        http.csrf().disable();
    }

}

package demo;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class DemoUserDetailService implements UserDetailsService {


    private final CustomerRepository customerRepository;    

    @Autowired
    public DemoUserDetailService(CustomerRepository customerRepository){
        this.customerRepository = customerRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        Customer customer = customerRepository.findByUsername(username).get();

        boolean enabled = true;
        boolean accountNonExpired = true;
        boolean credentialsNonExpired = true;
        boolean accountNonLocked = true;

        return new User(
                customer.getUsername(),
                customer.getPassword(),
                enabled,
                accountNonExpired,
                credentialsNonExpired,
                accountNonLocked,
                Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"))
                );
    }
}

package demo;

import java.util.Optional;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.security.access.prepost.PreAuthorize;

public interface CustomerRepository extends PagingAndSortingRepository<Customer, Long>{

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    Optional<Customer> findByUsername(String username);

}

package demo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Customer {

    @Id
    @GeneratedValue
    private long id;

    private String username;
    private String password;

    public Customer(){}

    public Customer(String username, String password){
        this.username = username;
        this.password = password;
    }

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

【问题讨论】:

    标签: java spring jpa spring-security spring-data-rest


    【解决方案1】:

    对 UserDetailsS​​ervice 使用另一种机制,例如通过 JDBC 等访问数据库,或者创建仅由 UserDetailsS​​ervice 使用且不包含任何安全注释的第二个存储库。

    【讨论】:

    • 你知道一个有效的例子吗?另一个 repo 不起作用,因为他们引用了其他 repos,所以我最终会得到相同的或已经构建的异常
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    • 2016-04-05
    • 2020-08-08
    • 2015-06-04
    • 2020-06-17
    • 2015-04-10
    • 2018-01-24
    相关资源
    最近更新 更多