【问题标题】:How to configure authentication in spring security for different users from two different tables?如何在spring security中为来自两个不同表的不同用户配置身份验证?
【发布时间】:2020-07-08 15:57:24
【问题描述】:

在我的 Spring Boot 应用程序中,我有 2 种不同类型的用户 - 用户和供应商,它们存储在我的 SQL DB 的不同表中。

我只允许访问返回 JWT 的 /user/login 和 /vendor/login。

我无法理解如何配置 spring security 在有人请求 /user/login 时仅检查 USERS 表,而在供应商请求 /vendor/login 时仅检查 VENDORS 表。这可能吗?如果没有,任何人都可以建议我如何配置 Spring Security 以对来自不同表的用户进行身份验证?

这是我当前的配置,仅对用户进行身份验证 -

@Configuration
@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService myUserDetailsService;   // this fetches data from the USERS table

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    // *** How do I configure this to check both VENDORS OR USERS table? ***
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
            .antMatchers("/user/auth/login").permitAll()
            .antMatchers("/vendor/auth/login").permitAll()
            .anyRequest().authenticated()
            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

我为用户和供应商实现了 UserDetailsS​​ervice。这是 userService 的实现 -

@Service
public class UserService implements UserDetailsService {

    @Autowired
    private UserRepository repository;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public UserService() {
    }

    public UserService(UserRepository repository) {
        this.repository = repository;
    }

    public Users findOne(String id) {
        Optional<Users> user = repository.findById(id);
        return user.orElse(null);
    }

    public List<Users> findAll() {
        List<Users> users = new ArrayList<>();
        repository.findAll().forEach(users::add);
        return users;
    }

    public Users insert(Users user) throws UnknownError {
        // somecode here
    }

    public Users update(String id, Users user) {
       // some code here
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        final Users user = findByEmail(username);
        if (user == null) {
            throw new UsernameNotFoundException("No user Found");
        }

        return new User(user.getEmail(), user.getPassword(), new ArrayList<>());
    }
}

这里是UserController(VendorController和这个类似)-

@RestController
@RequestMapping(path = "/user")
public class AuthController {

    @Autowired
    UserService service;

    @Autowired
    AuthenticationManager authenticationManager;

    @PostMapping(path = "/login")
    public ResponseEntity<?> login(@RequestBody AuthenticationRequest form) throws Exception {
        try {
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(form.getEmail(), form.getPassword()));
        } catch (Exception e) {
            throw new Exception("Incorrect Credentials");
        }

        final UserDetails user = service.loadUserByUsername(form.getEmail());
        Users returnedUser = service.insert(user);
        ResponseStructure response = new ResponseStructure(true, returnedUser);
        return ResponseEntity.ok(response);
    }

【问题讨论】:

    标签: java spring spring-boot authentication spring-security


    【解决方案1】:

    您可以让 UserService 查找两个存储库

    @Service
    public class UserService implements UserDetailsService {
    
        @Autowired
        private UserRepository userRepository;
    
        @Autowired
        private VendorRepository vendorRepository;
    
       // all the other stuff
    
        private Users findByUsername(String username){
            return userRepository.findByUserName(username);
        }
    
        private Vendors findByVendorName(String vendorName){
            return VendorRepository.findByVendorName(vendorName); // given you have such method declared in the Spring Data repository
        }
    
        @Override
        public UserDetails loadUserByName(String name) throws UsernameNotFoundException {
            Users user = findByUsername(name);
            if (user != null) {
                 return new User(user.getEmail(), user.getPassword(), new ArrayList<>());
            }
    
            Vendors vendor = findByVendorName(name);
    
            if (vendor != null) {
                 return new Vendor(vendor.getEmail(), vendor.getPassword(), new ArrayList<>());
            }
            else{
                   throw new UsernameNotFoundException("No user Found");
            }
    
        }
    }
    

    【讨论】:

    • 谢谢,但这不是一个理想的解决方案,因为我们首先要遍历 users 表,然后是 vendor 表,其次,如果供应商或用户有相同的名称和密码,那可能惹麻烦。
    • 注意到您的请求来自不同的登录网址。也许你可以添加一个 userType 到 AuthenticationRequest 并根据用户类型选择正确的存储库。
    • 您可以将 userType 属性添加为登录表单上的隐藏输入以使其简单 或者您可以将 HttpServletRequest 作为参数添加到登录方法并使用 getRequestURI() 来了解请求的位置来自
    猜你喜欢
    • 2018-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 2014-01-18
    相关资源
    最近更新 更多