Как настроить аутентификацию в весенней безопасности для разных пользователей из двух разных таблиц? - PullRequest
1 голос
/ 27 марта 2020

В моем весеннем загрузочном приложении у меня есть 2 разных типа пользователя - пользователь и поставщик, которые хранятся в разных таблицах в моей SQL БД.

У меня есть только доступ к / user / login и / vendor / login, который возвращает JWT.

Я не могу понять, как настроить Spring Security, чтобы проверять только таблицу USERS, когда кто-то запрашивает / user / login, и проверять только таблицу VENDORS, когда vendor запрашивает / vendor / login , Это возможно? Если не кто-нибудь может подсказать, как настроить 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();
    }
}

У меня есть реализации UserDetailsService для как пользователь, так и поставщик. Вот реализация для 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);
    }

1 Ответ

1 голос
/ 29 марта 2020

Вы можете заставить 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");
        }

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...