我可以使用两个不同的表通过Spring Security在Spring Boot应用程序中进行登录吗?

时间:2019-04-23 08:36:51

标签: spring-boot authentication spring-security

在我当前的项目中,我有两个单独的实体。

  1. 用户:-要对用户进行身份验证
  2. 客户:-对客户进行身份验证

我很困惑我们如何通过Spring Security为两个单独的实体管理同一项目中的登录过程?

截至目前,它与一个User实体合作,现在我必须在Customer表的帮助下为客户集成另一个登录。

有可能吗?

注意:-由于其他一些要求,我不能为用户和客户使用同一张表。

我正在共享一些代码以获取更多权限。

下面的代码是用户详细信息服务的实现。

private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);

private final UserLoginRepository userRepository;

public DomainUserDetailsService(UserLoginRepository userRepository) {
    this.userRepository = userRepository;
}

@Override
@Transactional
public UserDetails loadUserByUsername(final String login) {
    log.debug("Authenticating {}", login);

    if (new EmailValidator().isValid(login, null)) {
        Optional<User> userByEmailFromDatabase = userRepository.findOneWithAuthoritiesByLogin(login);
        return userByEmailFromDatabase.map(user -> createSpringSecurityUser(login, user))
            .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));
    }

    String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
    Optional<User> userByLoginFromDatabase = userRepository.findOneWithAuthoritiesByLogin(lowercaseLogin);
    return userByLoginFromDatabase.map(user -> createSpringSecurityUser(lowercaseLogin, user))
        .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));

}

private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {

    List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
        .map(authority -> new SimpleGrantedAuthority(authority.getName()))
        .collect(Collectors.toList());
    return new org.springframework.security.core.userdetails.User(user.getLogin(),
        user.getPassword(),
        grantedAuthorities);
}

}

下面是安全配置类的植入。

private final AuthenticationManagerBuilder authenticationManagerBuilder;

private final UserDetailsService userDetailsService;

private final TokenProvider tokenProvider;

private final CorsFilter corsFilter;

private final SecurityProblemSupport problemSupport;

public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService,TokenProvider tokenProvider,CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
    this.authenticationManagerBuilder = authenticationManagerBuilder;
    this.userDetailsService = userDetailsService;
    this.tokenProvider = tokenProvider;
    this.corsFilter = corsFilter;
    this.problemSupport = problemSupport;
}

@PostConstruct
public void init() {
    try {
        authenticationManagerBuilder
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    } catch (Exception e) {
        throw new BeanInitializationException("Security configuration failed", e);
    }
}

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

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

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
        .antMatchers(HttpMethod.OPTIONS, "/**")
        .antMatchers("/app/**/*.{js,html}")
        .antMatchers("/i18n/**")
        .antMatchers("/content/**")
        .antMatchers("/swagger-ui/index.html");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling()
        .authenticationEntryPoint(problemSupport)
        .accessDeniedHandler(problemSupport)
    .and()
        .csrf()
        .disable()
        .headers()
        .frameOptions()
        .disable()
    .and()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
        .authorizeRequests()
        .antMatchers("/api/register").permitAll()
        .antMatchers("/api/activate").permitAll()
        .antMatchers("/api/userLogin").permitAll()
        .antMatchers("/api/account/reset-password/init").permitAll()
        .antMatchers("/api/account/reset-password/finish").permitAll()
        .antMatchers("/api/**").authenticated()
        .antMatchers("/management/health").permitAll()
        .antMatchers("/management/info").permitAll()
        .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
        .antMatchers("/v2/api-docs/**").permitAll()
        .antMatchers("/swagger-resources/configuration/ui").permitAll()
        .antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN)
    .and()
        .apply(securityConfigurerAdapter());

}

private JWTConfigurer securityConfigurerAdapter() {
    return new JWTConfigurer(tokenProvider);
}

}

登录api

@PostMapping("/userLogin")
@Timed
public Response<JWTToken> authorize(
        @Valid @RequestBody UserLoginReq userLoginReq) {

    Map<String, Object> responseData = null;
    try {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                userLoginReq.getUsername(), userLoginReq.getPassword());

        Authentication authentication = this.authenticationManager
                .authenticate(authenticationToken);

        SecurityContextHolder.getContext()
                .setAuthentication(authentication);

}

2 个答案:

答案 0 :(得分:1)

起初客户也是用户,不是吗?因此,也许更简单的解决方案是同时以用户身份创建客户(使用某些flag / db字段usertype ={USER|CUSTOMER|...})。如果您仍然需要管理两个实体,那么您的方法是正确的,但是在DetailService中,只需实现另一个方法即可读取客户实体,然后创建spring的User。

答案 1 :(得分:0)

是的,您可以通过userName组合用户类型,并用如下字符分隔:

示例:

  1. String userName=inputUserName +":APP_USER";

  2. UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userName, password);

  3. UserDetailsService.loadUserByUsername(userName)中的
  4. 首先拆分得到userName部分,也得到userType部分。 现在,您可以基于userType来决定应该从哪个表对用户进行身份验证。

    String userNamePart = null;
    if (userName.contains(":")) {
        int colonIndex = userName.lastIndexOf(":");
        userNamePart = userName.substring(0, colonIndex);
    }
    userNamePart = userNamePart == null ? userName : userNamePart;
    
    
    String userTypePart = null;
    if (userName.contains(":")) {
        int colonIndex = userName.lastIndexOf(":");
        userTypePart = userName.substring(colonIndex + 1, userName.length());
    }