title: How to use spring security to authenticate two different types of users?
body: <p>In my spring boot application, I will have two different types of users i.e. </p>
  
  <ol>
  <li>Admin users </li>
  <li>customers</li>
  </ol>
  
  <p>These users will be stored in two different tables. 
  These two tables will have only email id in common. Everything else will be different. </p>
  
  <p>Also, the no. of customers will be huge like 1 to 5 Millions customers. While on the other hand, admin users will be very few like less than 10. Hence the two different tables. </p>
  
  <p>I want to have two different login pages. One at /customer/login for all the customer and another at /admin/login for all the admins. Login details should be authenticated using their respective tables. On login customers should go to /customer/home and admins should go to /admin/home. </p>
  
  <p>On logout customer should be redirected to /customer/login and admin to /admin/login</p>
  
  <p>I am using java config for Spring security. How can this be done in spring security?</p>
  
  <p>Below is my configuration for single user which works properly.</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
  public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  
      @Autowired
      private UserDetailsService userDetailsService;
  
      @Autowired
      private AccessDecisionManager accessDecisionManager;
  
      @Autowired
      private ApplicationProperties applicationProperties;
  
      @Bean
      public Integer applicationSessionTimeout(){
          return applicationProperties.getSecurity().getSessionTimeout();
      }
  
      @Bean
      @Autowired
      public AccessDecisionManager accessDecisionManager(AccessDecisionVoterImpl accessDecisionVoter) {
          List&lt;AccessDecisionVoter&lt;?&gt;&gt; accessDecisionVoters = new ArrayList&lt;AccessDecisionVoter&lt;?&gt;&gt;();
          accessDecisionVoters.add(new WebExpressionVoter());
          accessDecisionVoters.add(new AuthenticatedVoter());
          accessDecisionVoters.add(accessDecisionVoter);
          UnanimousBased accessDecisionManager = new UnanimousBased(accessDecisionVoters);
          return accessDecisionManager;
      }
  
      @Override
      @Autowired
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
      }
  
      @Bean
      public PasswordEncoder passwordEncoder(){
          PasswordEncoder passwordEncoder = new PasswordEncoder();
          passwordEncoder.setStringDigester(stringDigester());
          return passwordEncoder;
      }
  
      @Bean
      public PooledStringDigester stringDigester() {
          PooledStringDigester psd = new PooledStringDigester();
  
          psd.setPoolSize(2);
          psd.setAlgorithm("SHA-256");
          psd.setIterations(1000);
          psd.setSaltSizeBytes(16);
          psd.setSaltGenerator(randomSaltGenerator());
  
          return psd;
      }
  
      @Bean
      public RandomSaltGenerator randomSaltGenerator() {
          RandomSaltGenerator randomSaltGenerator = new RandomSaltGenerator();
          return randomSaltGenerator;
      }
  
      @Override
      public void configure(WebSecurity web) throws Exception {
          web.ignoring()
                  .antMatchers("/static/**")
                  .antMatchers("/i18n/**");
      }
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http
              .exceptionHandling().
                  accessDeniedPage("/accessDenied")
                  .and()
              .authorizeRequests()
                  .accessDecisionManager(accessDecisionManager)
                  .antMatchers("/login**").permitAll()
                  .antMatchers("/error**").permitAll()
                  .antMatchers("/checkLogin**").permitAll()
                  .anyRequest().fullyAuthenticated()
                  .and()
              .formLogin()
                  .loginPage("/login")
                  .loginProcessingUrl("/checkLogin")
                  .defaultSuccessUrl("/home?menu=homeMenuOption")
                  .failureUrl("/login?login_error=1")
                  .usernameParameter("username")
                  .passwordParameter("password")
                  .permitAll()
                  .and()
              .logout()
                  .logoutUrl("/logout")
                  .logoutSuccessHandler(new LogoutSuccessHandlerImpl())
                  .deleteCookies("JSESSIONID")
                  .invalidateHttpSession(true)
                  .permitAll()
                  .and()
              .headers()
                  .frameOptions()
                  .disable()
              .and()
                  .sessionManagement()
                  .maximumSessions(1);
      }
  
  }
  </code></pre>
  
  <p>Below is my UserDetailsService which checks in db for proper authentication.</p>
  
  <pre><code>@Service("userDetailsService")
  public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
  
      private static final Logger log = LoggerFactory.getLogger(UserDetailsService.class);
  
      @Autowired
      private UserService userService;
  
      @Autowired
      private ModuleService moduleService;
  
      @Override
      public UserDetails loadUserByUsername(final String userName) throws UsernameNotFoundException, DataAccessException {
          log.debug("Authenticating : {}", userName);
  
          SecurityUser securityUser = null;
  
          try {
  
              User user = userService.findUserByEmail(userName);
  
              if (user != null) {
                  log.debug("User with the username {} FOUND ", userName);
                  securityUser = new SecurityUser(user.getEmail(), user.getPassword(), true, true, true, true, getGrantedAuthorities(user.getRole().getId()));
                  securityUser.setUser(user);
              } else {
                  log.debug("User with the username {}  NOT FOUND", userName);
                  throw new UsernameNotFoundException("Username not found.");
              }
          } catch (Exception e) {
              log.error(e.getMessage(), e);
          }
  
          return securityUser;
      }
  
      private List&lt;GrantedAuthority&gt; getGrantedAuthorities(Long roleId) {
          log.debug("Populating user authorities");
  
          List&lt;GrantedAuthority&gt; authorities = new ArrayList&lt;GrantedAuthority&gt;();
          List&lt;Module&gt; allModules = moduleService.findAllModules();
          Map&lt;Long, Module&gt; moduleMap = new HashMap&lt;Long, Module&gt;();
  
          for(Module module : allModules){
              moduleMap.put(module.getModuleId(), module);
          }
  
          List&lt;ModuleOperation&gt; moduleOperationList = moduleService.findModuleOperationsByRoleId(roleId);
  
          for (ModuleOperation moduleOperation : moduleOperationList) {
              moduleOperation.setModuleName(moduleMap.get(moduleOperation.getModuleId()).getModuleName());
              authorities.add(moduleOperation);
          }
  
          return authorities;
      }
  }
  </code></pre>