2017-02-11 121 views
1

我很高兴你在这里读书,我的问题:)春季安全 - 双重身份验证:X.509终端,用户

我发展的春天启动一个Web应用程序的销售登录表单店。我创建了一个使用formLogin()作为用户身份验证(它像一个魅力)的登录系统,但是当涉及到检测用户在哪台计算机上登录时,我遇到了一个问题。另一个事实是,只有某些计算机应该能够访问该站点,并且只能访问一个用户。另外,我在数据库中实现了两个(用户和终端)链接到Spring-data JPA,并且终端对用户有一个外键(当没有人连接到它时为null)。

经过3天的搜索结果,我得出结论认为,实现这一目标的最佳方式是在每台计算机上安装X.509证书,以执行相互身份验证并为用户权限使用loginForm。 (终端没有权限,但配置像“这应该与收银机一起工作”或“这应该使用该收据打印机”)。

所以,代码部分... 这是我的实际春季安全配置:

@Configuration 
@EnableWebSecurity 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 

    @Autowired 
    UserDetailsService userDetailsService; 

    @Autowired 
    DataSource dataSource; 

    @Autowired 
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(userDetailsService); 
     auth.authenticationProvider(authenticationProvider()); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests() 
       .antMatchers("/", "/index", "/static/**", "/login", "/catalogo/**").permitAll() 
       .anyRequest().authenticated() 
       .and() 
      .formLogin() 
       .loginPage("/login") 
       .loginProcessingUrl("/login") 
       .usernameParameter("username") 
       .passwordParameter("password") 
       .and() 
      .logout() 
       .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) 
       .invalidateHttpSession(true) 
       .clearAuthentication(true) 
       .and() 
      .rememberMe() 
       .rememberMeParameter("remember-me") 
       .tokenRepository(persistentTokenRepository()) 
       .tokenValiditySeconds(86400).and() 
      .csrf() 
       .and() 
      .exceptionHandling().accessDeniedPage("/Access_Denied"); 
    } 

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

    @Bean 
    public DaoAuthenticationProvider authenticationProvider() { 
     DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); 
     authenticationProvider.setUserDetailsService(userDetailsService); 
     authenticationProvider.setPasswordEncoder(passwordEncoder()); 
     return authenticationProvider; 
    } 

    @Bean 
    public AuthenticationTrustResolver getAuthenticationTrustResolver() { 
     return new AuthenticationTrustResolverImpl(); 
    } 

    @Bean 
    public PersistentTokenRepository persistentTokenRepository() { 
     JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl(); 
     tokenRepositoryImpl.setDataSource(dataSource); 
     return tokenRepositoryImpl; 
    } 
} 

这是我UserDetailService:

@Service("customUserDetailsService") 
public class CustomUserDetailsService implements UserDetailsService { 
    private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class); 

    // This is my user model service in Spring-data JPA, I have one too for terminals 
    @Autowired 
    private SecurityUserService securityUserService; 

    @Transactional(readOnly=true) 
    public UserDetails loadUserByUsername(String username) 
      throws UsernameNotFoundException { 
     SecurityUser user = securityUserService.findByUsername(username); 
     logger.info("User : {}", user); 
     if(user==null){ 
      logger.info("User not found"); 
      throw new UsernameNotFoundException("Username not found"); 
     } 
     return new org.springframework.security.core.userdetails.User(
       user.getUsername(), user.getPassword(), true, true, true, 
       true, getGrantedAuthorities(getPermissions(user))); 
    } 

    private List<GrantedAuthority> getGrantedAuthorities(List<String> permisos) { 
     List<GrantedAuthority> authorities = new ArrayList<>(); 
     for (String permiso : permisos) { 
      authorities.add(new SimpleGrantedAuthority(permiso)); 
     } 
     return authorities; 
    } 

    private List<String> getPermissions(SecurityUser user) { 
     List<String> privileges = new ArrayList<>(); 
     List<SecurityPermission> collection = new ArrayList<>(); 

     for (SecurityRole role : user.getRoles()) { 
      collection.addAll(role.getPermissions()); 
     } 

     collection.addAll(user.getPermissions()); 

     for (SecurityPermission item : collection) { 
      privileges.add(item.getName()); 
     } 
     return privileges; 
    } 
} 

基本上现在我必须添加X .509证书认证。我没有使用登录表单并且运行良好,但我不知道如何处理这两者。

感谢您的帮助。

PS:如果你认为你有这个问题的另一种可能的解决方案,不要害怕它张贴

回答

0

如果你不打算使用客户端证书身份验证,以获得连接的用户的详细信息,那么你只需要建立一个具有双向认证的安全TLS通道。你并不需要修改你的Spring应用程序

配置,要求客户出示的证书的TLS通道。浏览器将提示用户从密钥库中选择一个。服务器将验证它,如果可以接受将稳固安全通道。

配置特定于每个服务器,因此请查找您的文档。

您需要在每台计算机上安装客户端证书,如果您使用的是自签名证书,也安装该公用部分的信任存储,以避免浏览器警告

这将有可能使用X509证书在客户端识别用户并避免登录表单。它需要为每个用户颁发证书并将其安装在用户要使用的计算机上。如果共享计算机,那么certifucates应该使用密码进行保护。可能不是你的好选择