[英]How to use spring security to authenticate two different types of users?
In my spring boot application, I will have two different types of users ie 在我的spring boot应用程序中,我将有两种不同类型的用户,即
These users will be stored in two different tables. 这些用户将存储在两个不同的表中。 These two tables will have only email id in common. 这两个表仅具有共同的电子邮件ID。 Everything else will be different. 其他一切都会有所不同。
Also, the no. 另外,没有。 of customers will be huge like 1 to 5 Millions customers. 的客户将是巨大的,如1-5百万客户。 While on the other hand, admin users will be very few like less than 10. Hence the two different tables. 另一方面,管理员用户很少,少于10个。因此,存在两个不同的表。
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. 对于所有客户,一个在/ customer / login上,对于所有管理员,一个在/ admin / login上。 Login details should be authenticated using their respective tables. 登录详细信息应使用其各自的表进行身份验证。 On login customers should go to /customer/home and admins should go to /admin/home. 登录时,客户应转到/ customer / home,管理员应转到/ admin / home。
On logout customer should be redirected to /customer/login and admin to /admin/login 注销时,应将客户重定向到/ customer / login,将admin重定向到/ admin / login
I am using java config for Spring security. 我正在为春季安全使用Java配置。 How can this be done in spring security? 在Spring Security中如何做到这一点?
Below is my configuration for single user which works properly. 以下是我的单用户配置,可以正常工作。
@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<AccessDecisionVoter<?>> accessDecisionVoters = new ArrayList<AccessDecisionVoter<?>>();
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);
}
}
Below is my UserDetailsService which checks in db for proper authentication. 下面是我的UserDetailsService,它在db中检查正确的身份验证。
@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<GrantedAuthority> getGrantedAuthorities(Long roleId) {
log.debug("Populating user authorities");
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
List<Module> allModules = moduleService.findAllModules();
Map<Long, Module> moduleMap = new HashMap<Long, Module>();
for(Module module : allModules){
moduleMap.put(module.getModuleId(), module);
}
List<ModuleOperation> moduleOperationList = moduleService.findModuleOperationsByRoleId(roleId);
for (ModuleOperation moduleOperation : moduleOperationList) {
moduleOperation.setModuleName(moduleMap.get(moduleOperation.getModuleId()).getModuleName());
authorities.add(moduleOperation);
}
return authorities;
}
}
It is really a bad idea to have different login pages for Spring security, because it is not the way it is designed for. 对于Spring安全性,拥有不同的登录页面确实是一个坏主意,因为这不是它设计的目的。 You are going to fall into trouble to define the authentication entry point to use and will need a lot of boiling plate. 您将难以定义要使用的身份验证入口点,并且将需要很多沸腾的盘子。 According to your other requirements, I would propose you the following way: 根据您的其他要求,我建议您采取以下方式:
AuthenticationManager
(the default ProviderManager
will be fine) 使用一个登录页面和一个AuthenticationManager
(默认的ProviderManager
会很好) AuthenticationProvider
s, both being DaoAuthenticationProvider
, each pointing on one of you 2 user tables 使用两个不同的AuthenticationProvider
对其进行配置,这两个都是DaoAuthenticationProvider
,每个都指向您2个用户表之一 That way you fully rely on SpringSecurity infrastructure with as little modifications as possible to meet your requirements. 这样,您就可以完全依靠SpringSecurity基础结构,并进行尽可能少的修改以满足您的需求。
But you should also wonder whether you really need different databases. 但是您还应该怀疑您是否真的需要其他数据库。 At least for the major providers (Oracle, PostgreSQL, MariaDB, ...) there is no harm in having many null columns in a record. 至少对于主要提供程序(Oracle,PostgreSQL,MariaDB等)而言,在记录中包含许多空列没有什么害处。 IMHO you should do a serious analysis to compare both ways, either one single table (much simpler to setup for Spring Security) or two tables. 恕我直言,您应该进行认真的分析以比较这两种方式,一个表(对于Spring Security而言,它更容易设置)或两个表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.